[SystemZ] Register compare-and-branch support
authorRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Tue, 28 May 2013 10:41:11 +0000 (10:41 +0000)
committerRichard Sandiford <rsandifo@linux.vnet.ibm.com>
Tue, 28 May 2013 10:41:11 +0000 (10:41 +0000)
This patch adds support for the CRJ and CGRJ instructions.  Support for
the immediate forms will be a separate patch.

The architecture has a large number of comparison instructions.  I think
it's generally better to concentrate on using the "best" comparison
instruction first and foremost, then only use something like CRJ if
CR really was the natual choice of comparison instruction.  The patch
therefore opportunistically converts separate CR and BRC instructions
into a single CRJ while emitting instructions in ISelLowering.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@182764 91177308-0d34-0410-b5e6-96231b3b80d8

26 files changed:
lib/Target/SystemZ/SystemZISelLowering.cpp
lib/Target/SystemZ/SystemZISelLowering.h
lib/Target/SystemZ/SystemZInstrFormats.td
lib/Target/SystemZ/SystemZInstrInfo.cpp
lib/Target/SystemZ/SystemZInstrInfo.h
lib/Target/SystemZ/SystemZInstrInfo.td
lib/Target/SystemZ/SystemZLongBranch.cpp
test/CodeGen/SystemZ/Large/branch-range-03.py [new file with mode: 0644]
test/CodeGen/SystemZ/Large/branch-range-04.py [new file with mode: 0644]
test/CodeGen/SystemZ/atomicrmw-minmax-01.ll
test/CodeGen/SystemZ/atomicrmw-minmax-02.ll
test/CodeGen/SystemZ/atomicrmw-minmax-03.ll
test/CodeGen/SystemZ/atomicrmw-minmax-04.ll
test/CodeGen/SystemZ/branch-02.ll
test/CodeGen/SystemZ/branch-06.ll [new file with mode: 0644]
test/CodeGen/SystemZ/branch-07.ll [new file with mode: 0644]
test/CodeGen/SystemZ/cmpxchg-01.ll
test/CodeGen/SystemZ/cmpxchg-02.ll
test/CodeGen/SystemZ/int-cmp-02.ll
test/CodeGen/SystemZ/int-cmp-07.ll
test/CodeGen/SystemZ/int-cmp-11.ll
test/CodeGen/SystemZ/int-cmp-13.ll
test/CodeGen/SystemZ/int-cmp-14.ll
test/MC/Disassembler/SystemZ/insns-pcrel.txt
test/MC/SystemZ/insn-bad.s
test/MC/SystemZ/insn-good.s

index f575911fad1cafff031991a52439670c28dd9acd..03a6da6dc42e4be430db270523fbc1be6a027cef 100644 (file)
@@ -1609,6 +1609,33 @@ static MachineBasicBlock *splitBlockAfter(MachineInstr *MI,
   return NewMBB;
 }
 
+bool SystemZTargetLowering::
+convertPrevCompareToBranch(MachineBasicBlock *MBB,
+                           MachineBasicBlock::iterator MBBI,
+                           unsigned CCMask, MachineBasicBlock *Target) const {
+  MachineBasicBlock::iterator Compare = MBBI;
+  MachineBasicBlock::iterator Begin = MBB->begin();
+  do
+    {
+      if (Compare == Begin)
+        return false;
+      --Compare;
+    }
+  while (Compare->isDebugValue());
+
+  const SystemZInstrInfo *TII = TM.getInstrInfo();
+  unsigned FusedOpcode = TII->getCompareAndBranch(Compare->getOpcode());
+  if (!FusedOpcode)
+    return false;
+
+  DebugLoc DL = Compare->getDebugLoc();
+  BuildMI(*MBB, MBBI, DL, TII->get(FusedOpcode))
+    .addOperand(Compare->getOperand(0)).addOperand(Compare->getOperand(1))
+    .addImm(CCMask).addMBB(Target);
+  Compare->removeFromParent();
+  return true;
+}
+
 // Implement EmitInstrWithCustomInserter for pseudo Select* instruction MI.
 MachineBasicBlock *
 SystemZTargetLowering::emitSelect(MachineInstr *MI,
@@ -1626,13 +1653,17 @@ SystemZTargetLowering::emitSelect(MachineInstr *MI,
   MachineBasicBlock *FalseMBB = emitBlockAfter(StartMBB);
 
   //  StartMBB:
-  //   ...
-  //   TrueVal = ...
-  //   cmpTY ccX, r1, r2
-  //   jCC JoinMBB
+  //   BRC CCMask, JoinMBB
   //   # fallthrough to FalseMBB
+  //
+  // The original DAG glues comparisons to their uses, both to ensure
+  // that no CC-clobbering instructions are inserted between them, and
+  // to ensure that comparison results are not reused.  This means that
+  // this Select is the sole user of any preceding comparison instruction
+  // and that we can try to use a fused compare and branch instead.
   MBB = StartMBB;
-  BuildMI(MBB, DL, TII->get(SystemZ::BRC)).addImm(CCMask).addMBB(JoinMBB);
+  if (!convertPrevCompareToBranch(MBB, MI, CCMask, JoinMBB))
+    BuildMI(MBB, DL, TII->get(SystemZ::BRC)).addImm(CCMask).addMBB(JoinMBB);
   MBB->addSuccessor(JoinMBB);
   MBB->addSuccessor(FalseMBB);
 
@@ -1854,10 +1885,17 @@ SystemZTargetLowering::emitAtomicLoadMinMax(MachineInstr *MI,
   if (IsSubWord)
     BuildMI(MBB, DL, TII->get(SystemZ::RLL), RotatedOldVal)
       .addReg(OldVal).addReg(BitShift).addImm(0);
-  BuildMI(MBB, DL, TII->get(CompareOpcode))
-    .addReg(RotatedOldVal).addReg(Src2);
-  BuildMI(MBB, DL, TII->get(SystemZ::BRC))
-    .addImm(KeepOldMask).addMBB(UpdateMBB);
+  unsigned FusedOpcode = TII->getCompareAndBranch(CompareOpcode);
+  if (FusedOpcode)
+    BuildMI(MBB, DL, TII->get(FusedOpcode))
+      .addReg(RotatedOldVal).addReg(Src2)
+      .addImm(KeepOldMask).addMBB(UpdateMBB);
+  else {
+    BuildMI(MBB, DL, TII->get(CompareOpcode))
+      .addReg(RotatedOldVal).addReg(Src2);
+    BuildMI(MBB, DL, TII->get(SystemZ::BRC))
+      .addImm(KeepOldMask).addMBB(UpdateMBB);
+  }
   MBB->addSuccessor(UpdateMBB);
   MBB->addSuccessor(UseAltMBB);
 
@@ -1959,8 +1997,7 @@ SystemZTargetLowering::emitAtomicCmpSwapW(MachineInstr *MI,
   //                      ^^ Replace the upper 32-BitSize bits of the
   //                         comparison value with those that we loaded,
   //                         so that we can use a full word comparison.
-  //   CR %Dest, %RetryCmpVal
-  //   JNE DoneMBB
+  //   CRJNE %Dest, %RetryCmpVal, DoneMBB
   //   # Fall through to SetMBB
   MBB = LoopMBB;
   BuildMI(MBB, DL, TII->get(SystemZ::PHI), OldVal)
@@ -1976,9 +2013,9 @@ SystemZTargetLowering::emitAtomicCmpSwapW(MachineInstr *MI,
     .addReg(OldVal).addReg(BitShift).addImm(BitSize);
   BuildMI(MBB, DL, TII->get(SystemZ::RISBG32), RetryCmpVal)
     .addReg(CmpVal).addReg(Dest).addImm(32).addImm(63 - BitSize).addImm(0);
-  BuildMI(MBB, DL, TII->get(SystemZ::CR))
-    .addReg(Dest).addReg(RetryCmpVal);
-  BuildMI(MBB, DL, TII->get(SystemZ::BRC)).addImm(MaskNE).addMBB(DoneMBB);
+  BuildMI(MBB, DL, TII->get(SystemZ::CRJ))
+    .addReg(Dest).addReg(RetryCmpVal)
+    .addImm(MaskNE).addMBB(DoneMBB);
   MBB->addSuccessor(DoneMBB);
   MBB->addSuccessor(SetMBB);
 
@@ -2227,6 +2264,16 @@ EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const {
 
   case SystemZ::ATOMIC_CMP_SWAPW:
     return emitAtomicCmpSwapW(MI, MBB);
+  case SystemZ::BRC:
+    // The original DAG glues comparisons to their uses, both to ensure
+    // that no CC-clobbering instructions are inserted between them, and
+    // to ensure that comparison results are not reused.  This means that
+    // a BRC is the sole user of a preceding comparison and that we can
+    // try to use a fused compare and branch instead.
+    if (convertPrevCompareToBranch(MBB, MI, MI->getOperand(0).getImm(),
+                                   MI->getOperand(1).getMBB()))
+      MI->eraseFromParent();
+    return MBB;
   default:
     llvm_unreachable("Unexpected instr type to insert");
   }
index e408bd280aa02942c235d7bff2572ba0009d61cf..129165df6a82cb96924328540f0ac2d9f9cb4817 100644 (file)
@@ -16,6 +16,7 @@
 #define LLVM_TARGET_SystemZ_ISELLOWERING_H
 
 #include "SystemZ.h"
+#include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/SelectionDAG.h"
 #include "llvm/Target/TargetLowering.h"
 
@@ -189,6 +190,15 @@ private:
   SDValue lowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerSTACKRESTORE(SDValue Op, SelectionDAG &DAG) const;
 
+  // If the last instruction before MBBI in MBB was some form of COMPARE,
+  // try to replace it with a COMPARE AND BRANCH just before MBBI.
+  // CCMask and Target are the BRC-like operands for the branch.
+  // Return true if the change was made.
+  bool convertPrevCompareToBranch(MachineBasicBlock *MBB,
+                                  MachineBasicBlock::iterator MBBI,
+                                  unsigned CCMask,
+                                  MachineBasicBlock *Target) const;
+
   // Implement EmitInstrWithCustomInserter for individual operation types.
   MachineBasicBlock *emitSelect(MachineInstr *MI,
                                 MachineBasicBlock *BB) const;
index a9bc5629d0e7131686f06cb85fcabcb06e2aab06..c52e2a29f3cf04864b626db7d1737ade96d01aa9 100644 (file)
@@ -110,6 +110,25 @@ class InstRI<bits<12> op, dag outs, dag ins, string asmstr, list<dag> pattern>
   let Inst{15-0}  = I2;
 }
 
+class InstRIEb<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> R2;
+  bits<4> M3;
+  bits<16> RI4;
+
+  let Inst{47-40} = op{15-8};
+  let Inst{39-36} = R1;
+  let Inst{35-32} = R2;
+  let Inst{31-16} = RI4;
+  let Inst{15-12} = M3;
+  let Inst{11-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;
index 6296e4a48007e34beb438392b64cb8edae994d86..dcce5a7b7f79c66e542f78b14c06c9ba6a8913d5 100644 (file)
@@ -132,6 +132,10 @@ bool SystemZInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
     if (!Branch.Target->isMBB())
       return true;
 
+    // Punt on compound branches.
+    if (Branch.Type != SystemZII::BranchNormal)
+      return true;
+
     if (Branch.CCMask == SystemZ::CCMASK_ANY) {
       // Handle unconditional branches.
       if (!AllowModify) {
@@ -361,11 +365,21 @@ SystemZInstrInfo::getBranchInfo(const MachineInstr *MI) const {
   case SystemZ::BR:
   case SystemZ::J:
   case SystemZ::JG:
-    return SystemZII::Branch(SystemZ::CCMASK_ANY, &MI->getOperand(0));
+    return SystemZII::Branch(SystemZII::BranchNormal, SystemZ::CCMASK_ANY,
+                             &MI->getOperand(0));
 
   case SystemZ::BRC:
   case SystemZ::BRCL:
-    return SystemZII::Branch(MI->getOperand(0).getImm(), &MI->getOperand(1));
+    return SystemZII::Branch(SystemZII::BranchNormal,
+                             MI->getOperand(0).getImm(), &MI->getOperand(1));
+
+  case SystemZ::CRJ:
+    return SystemZII::Branch(SystemZII::BranchC, MI->getOperand(2).getImm(),
+                             &MI->getOperand(3));
+
+  case SystemZ::CGRJ:
+    return SystemZII::Branch(SystemZII::BranchCG, MI->getOperand(2).getImm(),
+                             &MI->getOperand(3));
 
   default:
     llvm_unreachable("Unrecognized branch opcode");
@@ -426,6 +440,17 @@ unsigned SystemZInstrInfo::getOpcodeForOffset(unsigned Opcode,
   return 0;
 }
 
+unsigned SystemZInstrInfo::getCompareAndBranch(unsigned Opcode) const {
+  switch (Opcode) {
+  case SystemZ::CR:
+    return SystemZ::CRJ;
+  case SystemZ::CGR:
+    return SystemZ::CGRJ;
+  default:
+    return 0;
+  }
+}
+
 void SystemZInstrInfo::loadImmediate(MachineBasicBlock &MBB,
                                      MachineBasicBlock::iterator MBBI,
                                      unsigned Reg, uint64_t Value) const {
index 322219c52f598bdfe2494ef97dcfe5bf3c93606c..e4a984025f9a4369e63e7cb9f4ec6a062a016d36 100644 (file)
@@ -42,16 +42,32 @@ namespace SystemZII {
     // @GOT (aka @GOTENT)
     MO_GOT = (1 << 0)
   };
+  // Classifies a branch.
+  enum BranchType {
+    // An instruction that branches on the current value of CC.
+    BranchNormal,
+
+    // An instruction that peforms a 32-bit signed comparison and branches
+    // on the result.
+    BranchC,
+
+    // An instruction that peforms a 64-bit signed comparison and branches
+    // on the result.
+    BranchCG
+  };
   // Information about a branch instruction.
   struct Branch {
+    // The type of the branch.
+    BranchType Type;
+
     // CCMASK_<N> is set if the branch should be taken when CC == N.
     unsigned CCMask;
 
     // The target of the branch.
     const MachineOperand *Target;
 
-    Branch(unsigned ccMask, const MachineOperand *target)
-      : CCMask(ccMask), Target(target) {}
+    Branch(BranchType type, unsigned ccMask, const MachineOperand *target)
+      : Type(type), CCMask(ccMask), Target(target) {}
   };
 }
 
@@ -125,6 +141,10 @@ public:
   // exists.
   unsigned getOpcodeForOffset(unsigned Opcode, int64_t Offset) const;
 
+  // If Opcode is a COMPARE opcode for which an associated COMPARE AND
+  // BRANCH exists, return the opcode for the latter, otherwise return 0.
+  unsigned getCompareAndBranch(unsigned Opcode) const;
+
   // Emit code before MBBI in MI to move immediate value Value into
   // physical register Reg.
   void loadImmediate(MachineBasicBlock &MBB,
index a27d62bcf4f9924aa58c676d35f1c51bda3a6175..bc3997b857bd168ee52cbb6801d007314906b960 100644 (file)
@@ -58,25 +58,52 @@ let isBranch = 1, isTerminator = 1, isBarrier = 1, R1 = 15 in {
 // in their raw BRC/BRCL form, with the 4-bit condition-code mask being
 // the first operand.  It seems friendlier to use mnemonic forms like
 // JE and JLH when writing out the assembly though.
-multiclass CondBranches<Operand imm, string short, string long> {
+//
+// Using a custom inserter for BRC gives us a chance to convert the BRC
+// and a preceding compare into a single compare-and-branch instruction.
+// The inserter makes no change in cases where a separate branch really
+// is needed.
+multiclass CondBranches<Operand ccmask, string short, string long> {
   let isBranch = 1, isTerminator = 1, Uses = [CC] in {
-    def "" : InstRI<0xA74, (outs), (ins imm:$R1, brtarget16:$I2), short, []>;
-    def L  : InstRIL<0xC04, (outs), (ins imm:$R1, brtarget32:$I2), long, []>;
+    def "" : InstRI<0xA74, (outs), (ins ccmask:$R1, brtarget16:$I2), short, []>;
+    def L  : InstRIL<0xC04, (outs), (ins ccmask:$R1, brtarget32:$I2), long, []>;
   }
 }
-let isCodeGenOnly = 1 in
+let isCodeGenOnly = 1, usesCustomInserter = 1 in
   defm BRC : CondBranches<cond4, "j$R1\t$I2", "jg$R1\t$I2">;
 defm AsmBRC : CondBranches<uimm8zx4, "brc\t$R1, $I2", "brcl\t$R1, $I2">;
 
 def : Pat<(z_br_ccmask cond4:$cond, bb:$dst), (BRC cond4:$cond, bb:$dst)>;
 
-// Define AsmParser mnemonics for each condition code.
-multiclass CondExtendedMnemonic<bits<4> Cond, string name> {
-  let R1 = Cond in {
-    def "" : InstRI<0xA74, (outs), (ins brtarget16:$I2),
-                    "j"##name##"\t$I2", []>;
+// Fused compare-and-branch instructions.  As for normal branches,
+// we handle these instructions internally in their raw CRJ-like form,
+// but use assembly macros like CRJE when writing them out.
+//
+// These instructions do not use or clobber the condition codes.
+// We nevertheless pretend that they clobber CC, so that we can lower
+// them to separate comparisons and BRCLs if the branch ends up being
+// out of range.
+multiclass CompareBranches<Operand ccmask, string pos1, string pos2> {
+  let isBranch = 1, isTerminator = 1, Defs = [CC] in {
+    def RJ  : InstRIEb<0xEC76, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3,
+                                            brtarget16:$RI4),
+                       "crj"#pos1#"\t$R1, $R2, "#pos2#"$RI4", []>;
+    def GRJ : InstRIEb<0xEC64, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3,
+                                            brtarget16:$RI4),
+                       "cgrj"#pos1#"\t$R1, $R2, "#pos2#"$RI4", []>;
+  }
+}
+let isCodeGenOnly = 1 in
+  defm C : CompareBranches<cond4, "$M3", "">;
+defm AsmC : CompareBranches<uimm8zx4, "", "$M3, ">;
+
+// Define AsmParser mnemonics for each general condition-code mask
+// (integer or floating-point)
+multiclass CondExtendedMnemonic<bits<4> ccmask, string name> {
+  let R1 = ccmask in {
+    def "" : InstRI<0xA74, (outs), (ins brtarget16:$I2), "j"#name#"\t$I2", []>;
     def L  : InstRIL<0xC04, (outs), (ins brtarget32:$I2),
-                    "jg"##name##"\t$I2", []>;
+                     "jg"#name#"\t$I2", []>;
   }
 }
 defm AsmJO   : CondExtendedMnemonic<1,  "o">;
@@ -94,6 +121,35 @@ defm AsmJLE  : CondExtendedMnemonic<12, "le">;
 defm AsmJNH  : CondExtendedMnemonic<13, "nh">;
 defm AsmJNO  : CondExtendedMnemonic<14, "no">;
 
+// Define AsmParser mnemonics for each integer condition-code mask.
+// This is like the list above, except that condition 3 is not possible
+// and that the low bit of the mask is therefore always 0.  This means
+// that each condition has two names.  Conditions "o" and "no" are not used.
+//
+// We don't make one of the two names an alias of the other because
+// we need the custom parsing routines to select the correct register class.
+multiclass IntCondExtendedMnemonicA<bits<4> ccmask, string name> {
+  let M3 = ccmask in {
+    def CR  : InstRIEb<0xEC76, (outs), (ins GR32:$R1, GR32:$R2,
+                                            brtarget16:$RI4),
+                       "crj"##name##"\t$R1, $R2, $RI4", []>;
+    def CGR : InstRIEb<0xEC64, (outs), (ins GR64:$R1, GR64:$R2,
+                                            brtarget16:$RI4),
+                       "cgrj"##name##"\t$R1, $R2, $RI4", []>;
+  }
+}
+multiclass IntCondExtendedMnemonic<bits<4> ccmask, string name1, string name2>
+  : IntCondExtendedMnemonicA<ccmask, name1> {
+  let isAsmParserOnly = 1 in
+    defm Alt : IntCondExtendedMnemonicA<ccmask, name2>;
+}
+defm AsmJH   : IntCondExtendedMnemonic<2,  "h",  "nle">;
+defm AsmJL   : IntCondExtendedMnemonic<4,  "l",  "nhe">;
+defm AsmJLH  : IntCondExtendedMnemonic<6,  "lh", "ne">;
+defm AsmJE   : IntCondExtendedMnemonic<8,  "e",  "nlh">;
+defm AsmJHE  : IntCondExtendedMnemonic<10, "he", "nl">;
+defm AsmJLE  : IntCondExtendedMnemonic<12, "le", "nh">;
+
 def Select32 : SelectWrapper<GR32>;
 def Select64 : SelectWrapper<GR64>;
 
index 9db4f2d6006f3c68b36b2b0853b9870030f9986d..2fc85f50f0ffc8c0c28e661520c1bd1c18e62b68 100644 (file)
@@ -151,6 +151,7 @@ namespace {
     bool mustRelaxBranch(const TerminatorInfo &Terminator, uint64_t Address);
     bool mustRelaxABranch();
     void setWorstCaseAddresses();
+    void splitCompareBranch(MachineInstr *MI, unsigned CompareOpcode);
     void relaxBranch(TerminatorInfo &Terminator);
     void relaxBranches();
 
@@ -220,6 +221,14 @@ TerminatorInfo SystemZLongBranch::describeTerminator(MachineInstr *MI) {
       // Relaxes to BRCL, which is 2 bytes longer.
       Terminator.ExtraRelaxSize = 2;
       break;
+    case SystemZ::CRJ:
+      // Relaxes to a CR/BRCL sequence, which is 2 bytes longer.
+      Terminator.ExtraRelaxSize = 2;
+      break;
+    case SystemZ::CGRJ:
+      // Relaxes to a CGR/BRCL sequence, which is 4 bytes longer.
+      Terminator.ExtraRelaxSize = 4;
+      break;
     default:
       llvm_unreachable("Unrecognized branch instruction");
     }
@@ -319,6 +328,23 @@ void SystemZLongBranch::setWorstCaseAddresses() {
   }
 }
 
+// Split MI into the comparison given by CompareOpcode followed
+// a BRCL on the result.
+void SystemZLongBranch::splitCompareBranch(MachineInstr *MI,
+                                           unsigned CompareOpcode) {
+  MachineBasicBlock *MBB = MI->getParent();
+  DebugLoc DL = MI->getDebugLoc();
+  BuildMI(*MBB, MI, DL, TII->get(CompareOpcode))
+    .addOperand(MI->getOperand(0))
+    .addOperand(MI->getOperand(1));
+  MachineInstr *BRCL = BuildMI(*MBB, MI, DL, TII->get(SystemZ::BRCL))
+    .addOperand(MI->getOperand(2))
+    .addOperand(MI->getOperand(3));
+  // The implicit use of CC is a killing use.
+  BRCL->getOperand(2).setIsKill();
+  MI->eraseFromParent();
+}
+
 // Relax the branch described by Terminator.
 void SystemZLongBranch::relaxBranch(TerminatorInfo &Terminator) {
   MachineInstr *Branch = Terminator.Branch;
@@ -329,6 +355,12 @@ void SystemZLongBranch::relaxBranch(TerminatorInfo &Terminator) {
   case SystemZ::BRC:
     Branch->setDesc(TII->get(SystemZ::BRCL));
     break;
+  case SystemZ::CRJ:
+    splitCompareBranch(Branch, SystemZ::CR);
+    break;
+  case SystemZ::CGRJ:
+    splitCompareBranch(Branch, SystemZ::CGR);
+    break;
   default:
     llvm_unreachable("Unrecognized branch");
   }
diff --git a/test/CodeGen/SystemZ/Large/branch-range-03.py b/test/CodeGen/SystemZ/Large/branch-range-03.py
new file mode 100644 (file)
index 0000000..75cdf24
--- /dev/null
@@ -0,0 +1,107 @@
+# Test 32-bit COMPARE AND BRANCH in cases where the sheer number of
+# instructions causes some branches to be out of range.
+# RUN: python %s | llc -mtriple=s390x-linux-gnu | FileCheck %s
+
+# Construct:
+#
+# before0:
+#   conditional branch to after0
+#   ...
+# beforeN:
+#   conditional branch to after0
+# main:
+#   0xffcc bytes, from MVIY instructions
+#   conditional branch to main
+# after0:
+#   ...
+#   conditional branch to main
+# afterN:
+#
+# Each conditional branch sequence occupies 12 bytes if it uses a short
+# branch and 14 if it uses a long one.  The ones before "main:" have to
+# take the branch length into account, which is 6 for short branches,
+# so the final (0x34 - 6) / 12 == 3 blocks can use short branches.
+# The ones after "main:" do not, so the first 0x34 / 12 == 4 blocks
+# can use short branches.
+#
+# CHECK: lb [[REG:%r[0-5]]], 0(%r3)
+# CHECK: cr %r4, [[REG]]
+# CHECK: jge [[LABEL:\.L[^ ]*]]
+# CHECK: lb [[REG:%r[0-5]]], 1(%r3)
+# CHECK: cr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 2(%r3)
+# CHECK: cr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 3(%r3)
+# CHECK: cr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 4(%r3)
+# CHECK: cr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 5(%r3)
+# CHECK: crje %r4, [[REG]], [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 6(%r3)
+# CHECK: crje %r4, [[REG]], [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 7(%r3)
+# CHECK: crje %r4, [[REG]], [[LABEL]]
+# ...main goes here...
+# CHECK: lb [[REG:%r[0-5]]], 25(%r3)
+# CHECK: crje %r4, [[REG]], [[LABEL:\.L[^ ]*]]
+# CHECK: lb [[REG:%r[0-5]]], 26(%r3)
+# CHECK: crje %r4, [[REG]], [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 27(%r3)
+# CHECK: crje %r4, [[REG]], [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 28(%r3)
+# CHECK: crje %r4, [[REG]], [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 29(%r3)
+# CHECK: cr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 30(%r3)
+# CHECK: cr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 31(%r3)
+# CHECK: cr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lb [[REG:%r[0-5]]], 32(%r3)
+# CHECK: cr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+
+branch_blocks = 8
+main_size = 0xffcc
+
+print 'define void @f1(i8 *%base, i8 *%stop, i32 %limit) {'
+print 'entry:'
+print '  br label %before0'
+print ''
+
+for i in xrange(branch_blocks):
+    next = 'before%d' % (i + 1) if i + 1 < branch_blocks else 'main'
+    print 'before%d:' % i
+    print '  %%bstop%d = getelementptr i8 *%%stop, i64 %d' % (i, i)
+    print '  %%bcur%d = load volatile i8 *%%bstop%d' % (i, i)
+    print '  %%bext%d = sext i8 %%bcur%d to i32' % (i, i)
+    print '  %%btest%d = icmp eq i32 %%limit, %%bext%d' % (i, i)
+    print '  br i1 %%btest%d, label %%after0, label %%%s' % (i, next)
+    print ''
+
+print '%s:' % next
+a, b = 1, 1
+for i in xrange(0, main_size, 6):
+    a, b = b, a + b
+    offset = 4096 + b % 500000
+    value = a % 256
+    print '  %%ptr%d = getelementptr i8 *%%base, i64 %d' % (i, offset)
+    print '  store volatile i8 %d, i8 *%%ptr%d' % (value, i)
+
+for i in xrange(branch_blocks):
+    print '  %%astop%d = getelementptr i8 *%%stop, i64 %d' % (i, i + 25)
+    print '  %%acur%d = load volatile i8 *%%astop%d' % (i, i)
+    print '  %%aext%d = sext i8 %%acur%d to i32' % (i, i)
+    print '  %%atest%d = icmp eq i32 %%limit, %%aext%d' % (i, i)
+    print '  br i1 %%atest%d, label %%main, label %%after%d' % (i, i)
+    print ''
+    print 'after%d:' % i
+
+print '  ret void'
+print '}'
diff --git a/test/CodeGen/SystemZ/Large/branch-range-04.py b/test/CodeGen/SystemZ/Large/branch-range-04.py
new file mode 100644 (file)
index 0000000..3ae3ae9
--- /dev/null
@@ -0,0 +1,111 @@
+# Test 64-bit COMPARE AND BRANCH in cases where the sheer number of
+# instructions causes some branches to be out of range.
+# RUN: python %s | llc -mtriple=s390x-linux-gnu | FileCheck %s
+
+# Construct:
+#
+# before0:
+#   conditional branch to after0
+#   ...
+# beforeN:
+#   conditional branch to after0
+# main:
+#   0xffcc bytes, from MVIY instructions
+#   conditional branch to main
+# after0:
+#   ...
+#   conditional branch to main
+# afterN:
+#
+# Each conditional branch sequence occupies 12 bytes if it uses a short
+# branch and 16 if it uses a long one.  The ones before "main:" have to
+# take the branch length into account, which is 6 for short branches,
+# so the final (0x34 - 6) / 12 == 3 blocks can use short branches.
+# The ones after "main:" do not, so the first 0x34 / 12 == 4 blocks
+# can use short branches.  The conservative algorithm we use makes
+# one of the forward branches unnecessarily long, as noted in the
+# check output below.
+#
+# CHECK: lgb [[REG:%r[0-5]]], 0(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL:\.L[^ ]*]]
+# CHECK: lgb [[REG:%r[0-5]]], 1(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 2(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 3(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 4(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# ...as mentioned above, the next one could be a CGRJE instead...
+# CHECK: lgb [[REG:%r[0-5]]], 5(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 6(%r3)
+# CHECK: cgrje %r4, [[REG]], [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 7(%r3)
+# CHECK: cgrje %r4, [[REG]], [[LABEL]]
+# ...main goes here...
+# CHECK: lgb [[REG:%r[0-5]]], 25(%r3)
+# CHECK: cgrje %r4, [[REG]], [[LABEL:\.L[^ ]*]]
+# CHECK: lgb [[REG:%r[0-5]]], 26(%r3)
+# CHECK: cgrje %r4, [[REG]], [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 27(%r3)
+# CHECK: cgrje %r4, [[REG]], [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 28(%r3)
+# CHECK: cgrje %r4, [[REG]], [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 29(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 30(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 31(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+# CHECK: lgb [[REG:%r[0-5]]], 32(%r3)
+# CHECK: cgr %r4, [[REG]]
+# CHECK: jge [[LABEL]]
+
+branch_blocks = 8
+main_size = 0xffcc
+
+print 'define void @f1(i8 *%base, i8 *%stop, i64 %limit) {'
+print 'entry:'
+print '  br label %before0'
+print ''
+
+for i in xrange(branch_blocks):
+    next = 'before%d' % (i + 1) if i + 1 < branch_blocks else 'main'
+    print 'before%d:' % i
+    print '  %%bstop%d = getelementptr i8 *%%stop, i64 %d' % (i, i)
+    print '  %%bcur%d = load volatile i8 *%%bstop%d' % (i, i)
+    print '  %%bext%d = sext i8 %%bcur%d to i64' % (i, i)
+    print '  %%btest%d = icmp eq i64 %%limit, %%bext%d' % (i, i)
+    print '  br i1 %%btest%d, label %%after0, label %%%s' % (i, next)
+    print ''
+
+print '%s:' % next
+a, b = 1, 1
+for i in xrange(0, main_size, 6):
+    a, b = b, a + b
+    offset = 4096 + b % 500000
+    value = a % 256
+    print '  %%ptr%d = getelementptr i8 *%%base, i64 %d' % (i, offset)
+    print '  store volatile i8 %d, i8 *%%ptr%d' % (value, i)
+
+for i in xrange(branch_blocks):
+    print '  %%astop%d = getelementptr i8 *%%stop, i64 %d' % (i, i + 25)
+    print '  %%acur%d = load volatile i8 *%%astop%d' % (i, i)
+    print '  %%aext%d = sext i8 %%acur%d to i64' % (i, i)
+    print '  %%atest%d = icmp eq i64 %%limit, %%aext%d' % (i, i)
+    print '  br i1 %%atest%d, label %%main, label %%after%d' % (i, i)
+    print ''
+    print 'after%d:' % i
+
+print '  ret void'
+print '}'
index 83d6156c5dbd52880220a1b8b70e73ad7bfb6872..bf490d892949a67e38f7bf9e7783c4d34bad8723 100644 (file)
@@ -19,8 +19,7 @@ define i8 @f1(i8 *%src, i8 %b) {
 ; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
 ; CHECK: [[LOOP:\.[^:]*]]:
 ; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
-; CHECK: cr [[ROT]], %r3
-; CHECK: jle [[KEEP:\..*]]
+; CHECK: crjle [[ROT]], %r3, [[KEEP:\..*]]
 ; CHECK: risbg [[ROT]], %r3, 32, 39, 0
 ; CHECK: [[KEEP]]:
 ; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
@@ -40,7 +39,7 @@ define i8 @f1(i8 *%src, i8 %b) {
 ; CHECK-SHIFT2: f1:
 ; CHECK-SHIFT2: sll %r3, 24
 ; CHECK-SHIFT2: rll
-; CHECK-SHIFT2: cr {{%r[0-9]+}}, %r3
+; CHECK-SHIFT2: crjle {{%r[0-9]+}}, %r3
 ; CHECK-SHIFT2: rll
 ; CHECK-SHIFT2: rll
 ; CHECK-SHIFT2: br %r14
@@ -56,8 +55,7 @@ define i8 @f2(i8 *%src, i8 %b) {
 ; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
 ; CHECK: [[LOOP:\.[^:]*]]:
 ; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
-; CHECK: cr [[ROT]], %r3
-; CHECK: jhe [[KEEP:\..*]]
+; CHECK: crjhe [[ROT]], %r3, [[KEEP:\..*]]
 ; CHECK: risbg [[ROT]], %r3, 32, 39, 0
 ; CHECK: [[KEEP]]:
 ; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
@@ -77,7 +75,7 @@ define i8 @f2(i8 *%src, i8 %b) {
 ; CHECK-SHIFT2: f2:
 ; CHECK-SHIFT2: sll %r3, 24
 ; CHECK-SHIFT2: rll
-; CHECK-SHIFT2: cr {{%r[0-9]+}}, %r3
+; CHECK-SHIFT2: crjhe {{%r[0-9]+}}, %r3
 ; CHECK-SHIFT2: rll
 ; CHECK-SHIFT2: rll
 ; CHECK-SHIFT2: br %r14
@@ -164,7 +162,7 @@ define i8 @f4(i8 *%src, i8 %b) {
 define i8 @f5(i8 *%src) {
 ; CHECK: f5:
 ; CHECK: llilh [[SRC2:%r[0-9]+]], 33024
-; CHECK: cr [[ROT:%r[0-9]+]], [[SRC2]]
+; CHECK: crjle [[ROT:%r[0-9]+]], [[SRC2]]
 ; CHECK: risbg [[ROT]], [[SRC2]], 32, 39, 0
 ; CHECK: br %r14
 ;
@@ -181,7 +179,7 @@ define i8 @f5(i8 *%src) {
 define i8 @f6(i8 *%src) {
 ; CHECK: f6:
 ; CHECK: llilh [[SRC2:%r[0-9]+]], 32256
-; CHECK: cr [[ROT:%r[0-9]+]], [[SRC2]]
+; CHECK: crjhe [[ROT:%r[0-9]+]], [[SRC2]]
 ; CHECK: risbg [[ROT]], [[SRC2]], 32, 39, 0
 ; CHECK: br %r14
 ;
index 27dc3e925b3620f7526c30111ebd2a3e60d39c27..b2c7bc90288bd222cad6bc8a5794126ab5603286 100644 (file)
@@ -19,8 +19,7 @@ define i16 @f1(i16 *%src, i16 %b) {
 ; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
 ; CHECK: [[LOOP:\.[^:]*]]:
 ; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
-; CHECK: cr [[ROT]], %r3
-; CHECK: jle [[KEEP:\..*]]
+; CHECK: crjle [[ROT]], %r3, [[KEEP:\..*]]
 ; CHECK: risbg [[ROT]], %r3, 32, 47, 0
 ; CHECK: [[KEEP]]:
 ; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
@@ -40,7 +39,7 @@ define i16 @f1(i16 *%src, i16 %b) {
 ; CHECK-SHIFT2: f1:
 ; CHECK-SHIFT2: sll %r3, 16
 ; CHECK-SHIFT2: rll
-; CHECK-SHIFT2: cr {{%r[0-9]+}}, %r3
+; CHECK-SHIFT2: crjle {{%r[0-9]+}}, %r3
 ; CHECK-SHIFT2: rll
 ; CHECK-SHIFT2: rll
 ; CHECK-SHIFT2: br %r14
@@ -56,8 +55,7 @@ define i16 @f2(i16 *%src, i16 %b) {
 ; CHECK: l [[OLD:%r[0-9]+]], 0(%r2)
 ; CHECK: [[LOOP:\.[^:]*]]:
 ; CHECK: rll [[ROT:%r[0-9]+]], [[OLD]], 0([[SHIFT]])
-; CHECK: cr [[ROT]], %r3
-; CHECK: jhe [[KEEP:\..*]]
+; CHECK: crjhe [[ROT]], %r3, [[KEEP:\..*]]
 ; CHECK: risbg [[ROT]], %r3, 32, 47, 0
 ; CHECK: [[KEEP]]:
 ; CHECK: rll [[NEW:%r[0-9]+]], [[ROT]], 0({{%r[1-9]+}})
@@ -77,7 +75,7 @@ define i16 @f2(i16 *%src, i16 %b) {
 ; CHECK-SHIFT2: f2:
 ; CHECK-SHIFT2: sll %r3, 16
 ; CHECK-SHIFT2: rll
-; CHECK-SHIFT2: cr {{%r[0-9]+}}, %r3
+; CHECK-SHIFT2: crjhe {{%r[0-9]+}}, %r3
 ; CHECK-SHIFT2: rll
 ; CHECK-SHIFT2: rll
 ; CHECK-SHIFT2: br %r14
@@ -164,7 +162,7 @@ define i16 @f4(i16 *%src, i16 %b) {
 define i16 @f5(i16 *%src) {
 ; CHECK: f5:
 ; CHECK: llilh [[SRC2:%r[0-9]+]], 32769
-; CHECK: cr [[ROT:%r[0-9]+]], [[SRC2]]
+; CHECK: crjle [[ROT:%r[0-9]+]], [[SRC2]]
 ; CHECK: risbg [[ROT]], [[SRC2]], 32, 47, 0
 ; CHECK: br %r14
 ;
@@ -181,7 +179,7 @@ define i16 @f5(i16 *%src) {
 define i16 @f6(i16 *%src) {
 ; CHECK: f6:
 ; CHECK: llilh [[SRC2:%r[0-9]+]], 32766
-; CHECK: cr [[ROT:%r[0-9]+]], [[SRC2]]
+; CHECK: crjhe [[ROT:%r[0-9]+]], [[SRC2]]
 ; CHECK: risbg [[ROT]], [[SRC2]], 32, 47, 0
 ; CHECK: br %r14
 ;
index 53d0e737e0714a1313ec376767a5d979be5c830b..4f7d820adaf06b4afd01d7bad29a15a0e5bbac01 100644 (file)
@@ -7,9 +7,8 @@ define i32 @f1(i32 %dummy, i32 *%src, i32 %b) {
 ; CHECK: f1:
 ; CHECK: l %r2, 0(%r3)
 ; CHECK: [[LOOP:\.[^:]*]]:
-; CHECK: cr %r2, %r4
 ; CHECK: lr [[NEW:%r[0-9]+]], %r2
-; CHECK: jle [[KEEP:\..*]]
+; CHECK: crjle %r2, %r4, [[KEEP:\..*]]
 ; CHECK: lr [[NEW]], %r4
 ; CHECK: cs %r2, [[NEW]], 0(%r3)
 ; CHECK: jlh [[LOOP]]
@@ -23,9 +22,8 @@ define i32 @f2(i32 %dummy, i32 *%src, i32 %b) {
 ; CHECK: f2:
 ; CHECK: l %r2, 0(%r3)
 ; CHECK: [[LOOP:\.[^:]*]]:
-; CHECK: cr %r2, %r4
 ; CHECK: lr [[NEW:%r[0-9]+]], %r2
-; CHECK: jhe [[KEEP:\..*]]
+; CHECK: crjhe %r2, %r4, [[KEEP:\..*]]
 ; CHECK: lr [[NEW]], %r4
 ; CHECK: cs %r2, [[NEW]], 0(%r3)
 ; CHECK: jlh [[LOOP]]
@@ -164,9 +162,8 @@ define i32 @f13(i32 %dummy, i32 *%ptr) {
 ; CHECK: lhi [[LIMIT:%r[0-9]+]], 42
 ; CHECK: l %r2, 0(%r3)
 ; CHECK: [[LOOP:\.[^:]*]]:
-; CHECK: cr %r2, [[LIMIT]]
 ; CHECK: lr [[NEW:%r[0-9]+]], %r2
-; CHECK: jle [[KEEP:\..*]]
+; CHECK: crjle %r2, [[LIMIT]], [[KEEP:\..*]]
 ; CHECK: lr [[NEW]], [[LIMIT]]
 ; CHECK: cs %r2, [[NEW]], 0(%r3)
 ; CHECK: jlh [[LOOP]]
index d77233141807ed1839b1ab756c5a134c07995dab..cd35ab019e0f56ff124b7f1d540978f5f3dbc09f 100644 (file)
@@ -7,9 +7,8 @@ define i64 @f1(i64 %dummy, i64 *%src, i64 %b) {
 ; CHECK: f1:
 ; CHECK: lg %r2, 0(%r3)
 ; CHECK: [[LOOP:\.[^:]*]]:
-; CHECK: cgr %r2, %r4
 ; CHECK: lgr [[NEW:%r[0-9]+]], %r2
-; CHECK: jle [[KEEP:\..*]]
+; CHECK: cgrjle %r2, %r4, [[KEEP:\..*]]
 ; CHECK: lgr [[NEW]], %r4
 ; CHECK: csg %r2, [[NEW]], 0(%r3)
 ; CHECK: jlh [[LOOP]]
@@ -23,9 +22,8 @@ define i64 @f2(i64 %dummy, i64 *%src, i64 %b) {
 ; CHECK: f2:
 ; CHECK: lg %r2, 0(%r3)
 ; CHECK: [[LOOP:\.[^:]*]]:
-; CHECK: cgr %r2, %r4
 ; CHECK: lgr [[NEW:%r[0-9]+]], %r2
-; CHECK: jhe [[KEEP:\..*]]
+; CHECK: cgrjhe %r2, %r4, [[KEEP:\..*]]
 ; CHECK: lgr [[NEW]], %r4
 ; CHECK: csg %r2, [[NEW]], 0(%r3)
 ; CHECK: jlh [[LOOP]]
@@ -131,9 +129,8 @@ define i64 @f10(i64 %dummy, i64 *%ptr) {
 ; CHECK: lghi [[LIMIT:%r[0-9]+]], 42
 ; CHECK: lg %r2, 0(%r3)
 ; CHECK: [[LOOP:\.[^:]*]]:
-; CHECK: cgr %r2, [[LIMIT]]
 ; CHECK: lgr [[NEW:%r[0-9]+]], %r2
-; CHECK: jle [[KEEP:\..*]]
+; CHECK: cgrjle %r2, [[LIMIT]], [[KEEP:\..*]]
 ; CHECK: lgr [[NEW]], [[LIMIT]]
 ; CHECK: csg %r2, [[NEW]], 0(%r3)
 ; CHECK: jlh [[LOOP]]
index 9365f16143090c7cf3548390da633779d4fea63e..9f71c053c7beedee39ced2f906d6db533c592522 100644 (file)
@@ -1,5 +1,6 @@
 ; Test all condition-code masks that are relevant for signed integer
-; comparisons.
+; comparisons, in cases where a separate branch is better than COMPARE
+; AND BRANCH.
 ;
 ; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
 
diff --git a/test/CodeGen/SystemZ/branch-06.ll b/test/CodeGen/SystemZ/branch-06.ll
new file mode 100644 (file)
index 0000000..3854045
--- /dev/null
@@ -0,0 +1,89 @@
+; Test all condition-code masks that are relevant for CRJ.
+;
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+
+declare i32 @foo();
+
+define void @f1(i32 %target) {
+; CHECK: f1:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: crje %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i32 @foo()
+  %cond = icmp eq i32 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f2(i32 %target) {
+; CHECK: f2:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: crjlh %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i32 @foo()
+  %cond = icmp ne i32 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f3(i32 %target) {
+; CHECK: f3:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: crjle %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i32 @foo()
+  %cond = icmp sle i32 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f4(i32 %target) {
+; CHECK: f4:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: crjl %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i32 @foo()
+  %cond = icmp slt i32 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f5(i32 %target) {
+; CHECK: f5:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: crjh %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i32 @foo()
+  %cond = icmp sgt i32 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f6(i32 %target) {
+; CHECK: f6:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: crjhe %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i32 @foo()
+  %cond = icmp sge i32 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
diff --git a/test/CodeGen/SystemZ/branch-07.ll b/test/CodeGen/SystemZ/branch-07.ll
new file mode 100644 (file)
index 0000000..1cab6ff
--- /dev/null
@@ -0,0 +1,89 @@
+; Test all condition-code masks that are relevant for CGRJ.
+;
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+
+declare i64 @foo();
+
+define void @f1(i64 %target) {
+; CHECK: f1:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: cgrje %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i64 @foo()
+  %cond = icmp eq i64 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f2(i64 %target) {
+; CHECK: f2:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: cgrjlh %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i64 @foo()
+  %cond = icmp ne i64 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f3(i64 %target) {
+; CHECK: f3:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: cgrjle %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i64 @foo()
+  %cond = icmp sle i64 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f4(i64 %target) {
+; CHECK: f4:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: cgrjl %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i64 @foo()
+  %cond = icmp slt i64 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f5(i64 %target) {
+; CHECK: f5:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: cgrjh %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i64 @foo()
+  %cond = icmp sgt i64 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
+
+define void @f6(i64 %target) {
+; CHECK: f6:
+; CHECK: .cfi_def_cfa_offset
+; CHECK: .L[[LABEL:.*]]:
+; CHECK: cgrjhe %r2, {{%r[0-9]+}}, .L[[LABEL]]
+  br label %loop
+loop:
+  %val = call i64 @foo()
+  %cond = icmp sge i64 %val, %target
+  br i1 %cond, label %loop, label %exit
+exit:
+  ret void
+}
index e8488615bd1a60af94be5ce54cdc9d340b4ecc8b..03fabee132896325977b7bf906155551d7d3bf28 100644 (file)
@@ -18,8 +18,7 @@ define i8 @f1(i8 %dummy, i8 *%src, i8 %cmp, i8 %swap) {
 ; CHECK-MAIN: [[LOOP:\.[^ ]*]]:
 ; CHECK-MAIN: rll %r2, [[OLD]], 8([[SHIFT]])
 ; CHECK-MAIN: risbg %r4, %r2, 32, 55, 0
-; CHECK-MAIN: cr %r2, %r4
-; CHECK-MAIN: jlh [[EXIT:\.[^ ]*]]
+; CHECK-MAIN: crjlh %r2, %r4, [[EXIT:\.[^ ]*]]
 ; CHECK-MAIN: risbg %r5, %r2, 32, 55, 0
 ; CHECK-MAIN: rll [[NEW:%r[0-9]+]], %r5, -8({{%r[1-9]+}})
 ; CHECK-MAIN: cs [[OLD]], [[NEW]], 0(%r3)
index 2c2f76cd7c101a25f461785a60e564001e732aec..b5005bb291ed54a0ec8b752e6704d2b3464890e0 100644 (file)
@@ -18,8 +18,7 @@ define i16 @f1(i16 %dummy, i16 *%src, i16 %cmp, i16 %swap) {
 ; CHECK-MAIN: [[LOOP:\.[^ ]*]]:
 ; CHECK-MAIN: rll %r2, [[OLD]], 16([[SHIFT]])
 ; CHECK-MAIN: risbg %r4, %r2, 32, 47, 0
-; CHECK-MAIN: cr %r2, %r4
-; CHECK-MAIN: jlh [[EXIT:\.[^ ]*]]
+; CHECK-MAIN: crjlh %r2, %r4, [[EXIT:\.[^ ]*]]
 ; CHECK-MAIN: risbg %r5, %r2, 32, 47, 0
 ; CHECK-MAIN: rll [[NEW:%r[0-9]+]], %r5, -16({{%r[1-9]+}})
 ; CHECK-MAIN: cs [[OLD]], [[NEW]], 0(%r3)
index 262ade0b99bc52bfb8c6b6ff072b481406a95674..b98661ed4dd366e6732922818fac427881bb6389 100644 (file)
@@ -5,8 +5,7 @@
 ; Check register comparison.
 define double @f1(double %a, double %b, i32 %i1, i32 %i2) {
 ; CHECK: f1:
-; CHECK: cr %r2, %r3
-; CHECK-NEXT: jl
+; CHECK: crjl %r2, %r3
 ; CHECK: ldr %f0, %f2
 ; CHECK: br %r14
   %cond = icmp slt i32 %i1, %i2
index 6e626bca7f119ad02847ffd0f07e7f62a1fd5d44..48ccf5cb30b6ca261cdc4467560d0573ee9b2cc1 100644 (file)
@@ -5,8 +5,7 @@
 ; Check CGR.
 define double @f1(double %a, double %b, i64 %i1, i64 %i2) {
 ; CHECK: f1:
-; CHECK: cgr %r2, %r3
-; CHECK-NEXT: jl
+; CHECK: cgrjl %r2, %r3
 ; CHECK: ldr %f0, %f2
 ; CHECK: br %r14
   %cond = icmp slt i64 %i1, %i2
index 876882ea8f31154a78ade4600c6a0c3d180a33ab..64386f05d1e935f20e33735fe1ebefe6c76705a7 100644 (file)
@@ -65,8 +65,7 @@ define double @f5(double %a, double %b, i64 %i1) {
 ; Check the next value up, which must use register comparison.
 define double @f6(double %a, double %b, i64 %i1) {
 ; CHECK: f6:
-; CHECK: cgr
-; CHECK-NEXT: jl
+; CHECK: cgrjl
 ; CHECK: ldr %f0, %f2
 ; CHECK: br %r14
   %cond = icmp slt i64 %i1, 2147483648
@@ -125,8 +124,7 @@ define double @f10(double %a, double %b, i64 %i1) {
 ; Check the next value down, which must use register comparison.
 define double @f11(double %a, double %b, i64 %i1) {
 ; CHECK: f11:
-; CHECK: cgr
-; CHECK-NEXT: jl
+; CHECK: cgrjl
 ; CHECK: ldr %f0, %f2
 ; CHECK: br %r14
   %cond = icmp slt i64 %i1, -2147483649
index 0eec8903056a281ee86810e74c533c57c75f4fc5..aab95473a00ca26178964e37400198c447f243c0 100644 (file)
@@ -77,8 +77,7 @@ define double @f6(double %a, double %b, i64 %i1) {
 ; Check the next value up, which must use a register comparison.
 define double @f7(double %a, double %b, i64 %i1) {
 ; CHECK: f7:
-; CHECK: cgr %r2,
-; CHECK-NEXT: je
+; CHECK: cgrje %r2,
 ; CHECK: ldr %f0, %f2
 ; CHECK: br %r14
   %cond = icmp eq i64 %i1, 4294967296
@@ -137,8 +136,7 @@ define double @f11(double %a, double %b, i64 %i1) {
 ; Check the next value down, which must use register comparison.
 define double @f12(double %a, double %b, i64 %i1) {
 ; CHECK: f12:
-; CHECK: cgr
-; CHECK-NEXT: je
+; CHECK: cgrje
 ; CHECK: ldr %f0, %f2
 ; CHECK: br %r14
   %cond = icmp eq i64 %i1, -2147483649
index e3a561e38aaf847a69b7898b5c48de33c94f0a4a..28c325c005ea715ab11f04b8b6eedd2b973251f4 100644 (file)
@@ -77,8 +77,7 @@ define double @f6(double %a, double %b, i64 %i1) {
 ; Check the next value up, which must use a register comparison.
 define double @f7(double %a, double %b, i64 %i1) {
 ; CHECK: f7:
-; CHECK: cgr %r2,
-; CHECK-NEXT: jlh
+; CHECK: cgrjlh %r2,
 ; CHECK: ldr %f0, %f2
 ; CHECK: br %r14
   %cond = icmp ne i64 %i1, 4294967296
@@ -137,8 +136,7 @@ define double @f11(double %a, double %b, i64 %i1) {
 ; Check the next value down, which must use register comparison.
 define double @f12(double %a, double %b, i64 %i1) {
 ; CHECK: f12:
-; CHECK: cgr
-; CHECK-NEXT: jlh
+; CHECK: cgrjlh
 ; CHECK: ldr %f0, %f2
 ; CHECK: br %r14
   %cond = icmp ne i64 %i1, -2147483649
index 1f2d8d0094dbb03f73f8bd7531f1007854846132..0b135377f343d07005c9d4fc60141f87c9770e33 100644 (file)
 # CHECK: strl %r15, 0x100000530
 0xc4 0xff 0x7f 0xff 0xff 0xff
 
+# 0x00000538:
+# CHECK: cgrj %r0, %r0, 0, 0x538
+0xec 0x00 0x00 0x00 0x00 0x64
+
+# 0x0000053e:
+# CHECK: cgrj %r0, %r15, 0, 0x53e
+0xec 0x0f 0x00 0x00 0x00 0x64
+
+# 0x00000544:
+# CHECK: cgrj %r15, %r0, 0, 0x544
+0xec 0xf0 0x00 0x00 0x00 0x64
+
+# 0x0000054a:
+# CHECK: cgrj %r7, %r8, 0, 0x54a
+0xec 0x78 0x00 0x00 0x00 0x64
+
+# 0x00000550:
+# CHECK: cgrj %r0, %r0, 0, 0x54e
+0xec 0x00 0xff 0xff 0x00 0x64
+
+# 0x00000556:
+# CHECK: cgrj %r0, %r0, 0, 0xffffffffffff0556
+0xec 0x00 0x80 0x00 0x00 0x64
+
+# 0x0000055c:
+# CHECK: cgrj %r0, %r0, 0, 0x1055a
+0xec 0x00 0x7f 0xff 0x00 0x64
+
+# 0x00000562:
+# CHECK: cgrj %r0, %r0, 1, 0x562
+0xec 0x00 0x00 0x00 0x10 0x64
+
+# 0x00000568:
+# CHECK: cgrjh %r0, %r0, 0x568
+0xec 0x00 0x00 0x00 0x20 0x64
+
+# 0x0000056e:
+# CHECK: cgrj %r0, %r0, 3, 0x56e
+0xec 0x00 0x00 0x00 0x30 0x64
+
+# 0x00000574:
+# CHECK: cgrjl %r0, %r0, 0x574
+0xec 0x00 0x00 0x00 0x40 0x64
+
+# 0x0000057a:
+# CHECK: cgrj %r0, %r0, 5, 0x57a
+0xec 0x00 0x00 0x00 0x50 0x64
+
+# 0x00000580:
+# CHECK: cgrjlh %r0, %r0, 0x580
+0xec 0x00 0x00 0x00 0x60 0x64
+
+# 0x00000586:
+# CHECK: cgrj %r0, %r0, 7, 0x586
+0xec 0x00 0x00 0x00 0x70 0x64
+
+# 0x0000058c:
+# CHECK: cgrje %r0, %r0, 0x58c
+0xec 0x00 0x00 0x00 0x80 0x64
+
+# 0x00000592:
+# CHECK: cgrj %r0, %r0, 9, 0x592
+0xec 0x00 0x00 0x00 0x90 0x64
+
+# 0x00000598:
+# CHECK: cgrjhe %r0, %r0, 0x598
+0xec 0x00 0x00 0x00 0xa0 0x64
+
+# 0x0000059e:
+# CHECK: cgrj %r0, %r0, 11, 0x59e
+0xec 0x00 0x00 0x00 0xb0 0x64
+
+# 0x000005a4:
+# CHECK: cgrjle %r0, %r0, 0x5a4
+0xec 0x00 0x00 0x00 0xc0 0x64
+
+# 0x000005aa:
+# CHECK: cgrj %r0, %r0, 13, 0x5aa
+0xec 0x00 0x00 0x00 0xd0 0x64
+
+# 0x000005b0:
+# CHECK: cgrj %r0, %r0, 14, 0x5b0
+0xec 0x00 0x00 0x00 0xe0 0x64
+
+# 0x000005b6:
+# CHECK: cgrj %r0, %r0, 15, 0x5b6
+0xec 0x00 0x00 0x00 0xf0 0x64
+
+# 0x000005bc:
+# CHECK: crj %r0, %r0, 0, 0x5bc
+0xec 0x00 0x00 0x00 0x00 0x76
+
+# 0x000005c2:
+# CHECK: crj %r0, %r15, 0, 0x5c2
+0xec 0x0f 0x00 0x00 0x00 0x76
+
+# 0x000005c8:
+# CHECK: crj %r15, %r0, 0, 0x5c8
+0xec 0xf0 0x00 0x00 0x00 0x76
+
+# 0x000005ce:
+# CHECK: crj %r7, %r8, 0, 0x5ce
+0xec 0x78 0x00 0x00 0x00 0x76
+
+# 0x000005d4:
+# CHECK: crj %r0, %r0, 0, 0x5d2
+0xec 0x00 0xff 0xff 0x00 0x76
+
+# 0x000005da:
+# CHECK: crj %r0, %r0, 0, 0xffffffffffff05da
+0xec 0x00 0x80 0x00 0x00 0x76
+
+# 0x000005e0:
+# CHECK: crj %r0, %r0, 0, 0x105de
+0xec 0x00 0x7f 0xff 0x00 0x76
+
+# 0x000005e6:
+# CHECK: crj %r0, %r0, 1, 0x5e6
+0xec 0x00 0x00 0x00 0x10 0x76
+
+# 0x000005ec:
+# CHECK: crjh %r0, %r0, 0x5ec
+0xec 0x00 0x00 0x00 0x20 0x76
+
+# 0x000005f2:
+# CHECK: crj %r0, %r0, 3, 0x5f2
+0xec 0x00 0x00 0x00 0x30 0x76
+
+# 0x000005f8:
+# CHECK: crjl %r0, %r0, 0x5f8
+0xec 0x00 0x00 0x00 0x40 0x76
+
+# 0x000005fe:
+# CHECK: crj %r0, %r0, 5, 0x5fe
+0xec 0x00 0x00 0x00 0x50 0x76
+
+# 0x00000604:
+# CHECK: crjlh %r0, %r0, 0x604
+0xec 0x00 0x00 0x00 0x60 0x76
+
+# 0x0000060a:
+# CHECK: crj %r0, %r0, 7, 0x60a
+0xec 0x00 0x00 0x00 0x70 0x76
+
+# 0x00000610:
+# CHECK: crje %r0, %r0, 0x610
+0xec 0x00 0x00 0x00 0x80 0x76
+
+# 0x00000616:
+# CHECK: crj %r0, %r0, 9, 0x616
+0xec 0x00 0x00 0x00 0x90 0x76
+
+# 0x0000061c:
+# CHECK: crjhe %r0, %r0, 0x61c
+0xec 0x00 0x00 0x00 0xa0 0x76
+
+# 0x00000622:
+# CHECK: crj %r0, %r0, 11, 0x622
+0xec 0x00 0x00 0x00 0xb0 0x76
+
+# 0x00000628:
+# CHECK: crjle %r0, %r0, 0x628
+0xec 0x00 0x00 0x00 0xc0 0x76
+
+# 0x0000062e:
+# CHECK: crj %r0, %r0, 13, 0x62e
+0xec 0x00 0x00 0x00 0xd0 0x76
+
+# 0x00000634:
+# CHECK: crj %r0, %r0, 14, 0x634
+0xec 0x00 0x00 0x00 0xe0 0x76
+
+# 0x0000063a:
+# CHECK: crj %r0, %r0, 15, 0x63a
+0xec 0x00 0x00 0x00 0xf0 0x76
index f1d86db437a5c9addff8229e9e1f93d7a848ac8d..ea249119c799eeeed53cd84f24e2d3128fc284a6 100644 (file)
        cghsi   0, -32769
        cghsi   0, 32768
 
+#CHECK: error: offset out of range
+#CHECK: cgrj   %r0, %r0, 0, -0x100002
+#CHECK: error: offset out of range
+#CHECK: cgrj   %r0, %r0, 0, -1
+#CHECK: error: offset out of range
+#CHECK: cgrj   %r0, %r0, 0, 1
+#CHECK: error: offset out of range
+#CHECK: cgrj   %r0, %r0, 0, 0x10000
+
+       cgrj    %r0, %r0, 0, -0x100002
+       cgrj    %r0, %r0, 0, -1
+       cgrj    %r0, %r0, 0, 1
+       cgrj    %r0, %r0, 0, 0x10000
+
+#CHECK: error: invalid instruction
+#CHECK:        cgrjo   %r0, %r0, 0, 0
+#CHECK: error: invalid instruction
+#CHECK:        cgrjno  %r0, %r0, 0, 0
+
+       cgrjo   %r0, %r0, 0, 0
+       cgrjno  %r0, %r0, 0, 0
+
 #CHECK: error: offset out of range
 #CHECK: cgrl   %r0, -0x1000000002
 #CHECK: error: offset out of range
        cly     %r0, -524289
        cly     %r0, 524288
 
+#CHECK: error: offset out of range
+#CHECK: crj    %r0, %r0, 0, -0x100002
+#CHECK: error: offset out of range
+#CHECK: crj    %r0, %r0, 0, -1
+#CHECK: error: offset out of range
+#CHECK: crj    %r0, %r0, 0, 1
+#CHECK: error: offset out of range
+#CHECK: crj    %r0, %r0, 0, 0x10000
+
+       crj     %r0, %r0, 0, -0x100002
+       crj     %r0, %r0, 0, -1
+       crj     %r0, %r0, 0, 1
+       crj     %r0, %r0, 0, 0x10000
+
+#CHECK: error: invalid instruction
+#CHECK:        crjo    %r0, %r0, 0, 0
+#CHECK: error: invalid instruction
+#CHECK:        crjno   %r0, %r0, 0, 0
+
+       crjo    %r0, %r0, 0, 0
+       crjno   %r0, %r0, 0, 0
+
 #CHECK: error: offset out of range
 #CHECK: crl    %r0, -0x1000000002
 #CHECK: error: offset out of range
index 99548ab362cc13efe28ae9713df6339b676ec03a..8188de3b56328067b73ba45cf2f05ea325dc2894 100644 (file)
        cgr     %r15,%r0
        cgr     %r7,%r8
 
+#CHECK: cgrj   %r0, %r0, 0, .[[LAB:L.*]]       # encoding: [0xec,0x00,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+#CHECK: cgrj   %r0, %r15, 0, .[[LAB:L.*]]      # encoding: [0xec,0x0f,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+#CHECK: cgrj   %r15, %r0, 0, .[[LAB:L.*]]      # encoding: [0xec,0xf0,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+#CHECK: cgrj   %r7, %r8, 0, .[[LAB:L.*]]       # encoding: [0xec,0x78,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+       cgrj    %r0,%r0,0,0
+       cgrj    %r0,%r15,0,0
+       cgrj    %r15,%r0,0,0
+       cgrj    %r7,%r8,0,0
+
+#CHECK: cgrj   %r1, %r2, 0, .[[LAB:L.*]]-65536 # encoding: [0xec,0x12,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: (.[[LAB]]-65536)+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 0, -0x10000
+#CHECK: cgrj   %r1, %r2, 0, .[[LAB:L.*]]-2     # encoding: [0xec,0x12,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: (.[[LAB]]-2)+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 0, -2
+#CHECK: cgrj   %r1, %r2, 0, .[[LAB:L.*]]               # encoding: [0xec,0x12,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 0, 0
+#CHECK: cgrj   %r1, %r2, 0, .[[LAB:L.*]]+65534 # encoding: [0xec,0x12,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: (.[[LAB]]+65534)+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 0, 0xfffe
+
+#CHECK: cgrj   %r1, %r2, 0, foo                  # encoding: [0xec,0x12,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 0, foo
+
+#CHECK: cgrj   %r1, %r2, 1, foo                  # encoding: [0xec,0x12,A,A,0x10,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 1, foo
+
+#CHECK: cgrj   %r1, %r2, 2, foo                  # encoding: [0xec,0x12,A,A,0x20,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjh  %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x20,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjnle        %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x20,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 2, foo
+       cgrjh   %r1, %r2, foo
+       cgrjnle %r1, %r2, foo
+
+#CHECK: cgrj   %r1, %r2, 3, foo                  # encoding: [0xec,0x12,A,A,0x30,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 3, foo
+
+#CHECK: cgrj   %r1, %r2, 4, foo                  # encoding: [0xec,0x12,A,A,0x40,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjl  %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x40,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjnhe        %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x40,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 4, foo
+       cgrjl   %r1, %r2, foo
+       cgrjnhe %r1, %r2, foo
+
+#CHECK: cgrj   %r1, %r2, 5, foo                  # encoding: [0xec,0x12,A,A,0x50,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 5, foo
+
+#CHECK: cgrj   %r1, %r2, 6, foo                  # encoding: [0xec,0x12,A,A,0x60,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjlh %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x60,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjne %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x60,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 6, foo
+       cgrjlh  %r1, %r2, foo
+       cgrjne  %r1, %r2, foo
+
+#CHECK: cgrj   %r1, %r2, 7, foo                  # encoding: [0xec,0x12,A,A,0x70,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 7, foo
+
+#CHECK: cgrj   %r1, %r2, 8, foo                  # encoding: [0xec,0x12,A,A,0x80,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrje  %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x80,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjnlh        %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x80,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 8, foo
+       cgrje   %r1, %r2, foo
+       cgrjnlh %r1, %r2, foo
+
+#CHECK: cgrj   %r1, %r2, 9, foo                  # encoding: [0xec,0x12,A,A,0x90,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 9, foo
+
+#CHECK: cgrj   %r1, %r2, 10, foo                 # encoding: [0xec,0x12,A,A,0xa0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjhe %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0xa0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjnl %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0xa0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 10, foo
+       cgrjhe  %r1, %r2, foo
+       cgrjnl  %r1, %r2, foo
+
+#CHECK: cgrj   %r1, %r2, 11, foo                 # encoding: [0xec,0x12,A,A,0xb0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 11, foo
+
+#CHECK: cgrj   %r1, %r2, 12, foo                 # encoding: [0xec,0x12,A,A,0xc0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjle %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0xc0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: cgrjnh %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0xc0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 12, foo
+       cgrjle  %r1, %r2, foo
+       cgrjnh  %r1, %r2, foo
+
+#CHECK: cgrj   %r1, %r2, 13, foo                 # encoding: [0xec,0x12,A,A,0xd0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 13, foo
+
+#CHECK: cgrj   %r1, %r2, 14, foo                 # encoding: [0xec,0x12,A,A,0xe0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 14, foo
+
+#CHECK: cgrj   %r1, %r2, 15, foo                 # encoding: [0xec,0x12,A,A,0xf0,0x64]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 15, foo
+
+#CHECK: cgrj   %r1, %r2, 0, bar+100              # encoding: [0xec,0x12,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 0, bar+100
+
+#CHECK: cgrjh  %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x20,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjh   %r1, %r2, bar+100
+
+#CHECK: cgrjnle        %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x20,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjnle %r1, %r2, bar+100
+
+#CHECK: cgrjl  %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x40,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjl   %r1, %r2, bar+100
+
+#CHECK: cgrjnhe        %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x40,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjnhe %r1, %r2, bar+100
+
+#CHECK: cgrjlh %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x60,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjlh  %r1, %r2, bar+100
+
+#CHECK: cgrjne %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x60,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjne  %r1, %r2, bar+100
+
+#CHECK: cgrje  %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x80,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrje   %r1, %r2, bar+100
+
+#CHECK: cgrjnlh        %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x80,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjnlh %r1, %r2, bar+100
+
+#CHECK: cgrjhe %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0xa0,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjhe  %r1, %r2, bar+100
+
+#CHECK: cgrjnl %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0xa0,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjnl  %r1, %r2, bar+100
+
+#CHECK: cgrjle %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0xc0,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjle  %r1, %r2, bar+100
+
+#CHECK: cgrjnh %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0xc0,0x64]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       cgrjnh  %r1, %r2, bar+100
+
+#CHECK: cgrj   %r1, %r2, 0, bar@PLT              # encoding: [0xec,0x12,A,A,0x00,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrj    %r1, %r2, 0, bar@PLT
+
+#CHECK: cgrjh  %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x20,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjh   %r1, %r2, bar@PLT
+
+#CHECK: cgrjnle        %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x20,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjnle %r1, %r2, bar@PLT
+
+#CHECK: cgrjl  %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x40,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjl   %r1, %r2, bar@PLT
+
+#CHECK: cgrjnhe        %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x40,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjnhe %r1, %r2, bar@PLT
+
+#CHECK: cgrjlh %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x60,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjlh  %r1, %r2, bar@PLT
+
+#CHECK: cgrjne %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x60,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjne  %r1, %r2, bar@PLT
+
+#CHECK: cgrje  %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x80,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrje   %r1, %r2, bar@PLT
+
+#CHECK: cgrjnlh        %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x80,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjnlh %r1, %r2, bar@PLT
+
+#CHECK: cgrjhe %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0xa0,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjhe  %r1, %r2, bar@PLT
+
+#CHECK: cgrjnl %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0xa0,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjnl  %r1, %r2, bar@PLT
+
+#CHECK: cgrjle %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0xc0,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjle  %r1, %r2, bar@PLT
+
+#CHECK: cgrjnh %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0xc0,0x64]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       cgrjnh  %r1, %r2, bar@PLT
+
 #CHECK: cgrl   %r0, .[[LAB:L.*]]-4294967296 # encoding: [0xc6,0x08,A,A,A,A]
 #CHECK:  fixup A - offset: 2, value: (.[[LAB]]-4294967296)+2, kind: FK_390_PC32DBL
        cgrl    %r0, -0x100000000
        cr      %r15,%r0
        cr      %r7,%r8
 
+#CHECK: crj    %r0, %r0, 0, .[[LAB:L.*]]       # encoding: [0xec,0x00,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+#CHECK: crj    %r0, %r15, 0, .[[LAB:L.*]]      # encoding: [0xec,0x0f,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+#CHECK: crj    %r15, %r0, 0, .[[LAB:L.*]]      # encoding: [0xec,0xf0,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+#CHECK: crj    %r7, %r8, 0, .[[LAB:L.*]]       # encoding: [0xec,0x78,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+       crj     %r0,%r0,0,0
+       crj     %r0,%r15,0,0
+       crj     %r15,%r0,0,0
+       crj     %r7,%r8,0,0
+
+#CHECK: crj    %r1, %r2, 0, .[[LAB:L.*]]-65536 # encoding: [0xec,0x12,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: (.[[LAB]]-65536)+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 0, -0x10000
+#CHECK: crj    %r1, %r2, 0, .[[LAB:L.*]]-2     # encoding: [0xec,0x12,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: (.[[LAB]]-2)+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 0, -2
+#CHECK: crj    %r1, %r2, 0, .[[LAB:L.*]]               # encoding: [0xec,0x12,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: .[[LAB]]+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 0, 0
+#CHECK: crj    %r1, %r2, 0, .[[LAB:L.*]]+65534 # encoding: [0xec,0x12,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: (.[[LAB]]+65534)+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 0, 0xfffe
+
+#CHECK: crj    %r1, %r2, 0, foo                  # encoding: [0xec,0x12,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 0, foo
+
+#CHECK: crj    %r1, %r2, 1, foo                  # encoding: [0xec,0x12,A,A,0x10,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 1, foo
+
+#CHECK: crj    %r1, %r2, 2, foo                  # encoding: [0xec,0x12,A,A,0x20,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjh   %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x20,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjnle %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x20,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 2, foo
+       crjh    %r1, %r2, foo
+       crjnle  %r1, %r2, foo
+
+#CHECK: crj    %r1, %r2, 3, foo                  # encoding: [0xec,0x12,A,A,0x30,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 3, foo
+
+#CHECK: crj    %r1, %r2, 4, foo                  # encoding: [0xec,0x12,A,A,0x40,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjl   %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x40,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjnhe %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x40,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 4, foo
+       crjl    %r1, %r2, foo
+       crjnhe  %r1, %r2, foo
+
+#CHECK: crj    %r1, %r2, 5, foo                  # encoding: [0xec,0x12,A,A,0x50,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 5, foo
+
+#CHECK: crj    %r1, %r2, 6, foo                  # encoding: [0xec,0x12,A,A,0x60,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjlh  %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x60,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjne  %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x60,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 6, foo
+       crjlh   %r1, %r2, foo
+       crjne   %r1, %r2, foo
+
+#CHECK: crj    %r1, %r2, 7, foo                  # encoding: [0xec,0x12,A,A,0x70,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 7, foo
+
+#CHECK: crj    %r1, %r2, 8, foo                  # encoding: [0xec,0x12,A,A,0x80,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crje   %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x80,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjnlh %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0x80,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 8, foo
+       crje    %r1, %r2, foo
+       crjnlh  %r1, %r2, foo
+
+#CHECK: crj    %r1, %r2, 9, foo                  # encoding: [0xec,0x12,A,A,0x90,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 9, foo
+
+#CHECK: crj    %r1, %r2, 10, foo                 # encoding: [0xec,0x12,A,A,0xa0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjhe  %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0xa0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjnl  %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0xa0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 10, foo
+       crjhe   %r1, %r2, foo
+       crjnl   %r1, %r2, foo
+
+#CHECK: crj    %r1, %r2, 11, foo                 # encoding: [0xec,0x12,A,A,0xb0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 11, foo
+
+#CHECK: crj    %r1, %r2, 12, foo                 # encoding: [0xec,0x12,A,A,0xc0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjle  %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0xc0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+#CHECK: crjnh  %r1, %r2, foo                     # encoding: [0xec,0x12,A,A,0xc0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 12, foo
+       crjle   %r1, %r2, foo
+       crjnh   %r1, %r2, foo
+
+#CHECK: crj    %r1, %r2, 13, foo                 # encoding: [0xec,0x12,A,A,0xd0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 13, foo
+
+#CHECK: crj    %r1, %r2, 14, foo                 # encoding: [0xec,0x12,A,A,0xe0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 14, foo
+
+#CHECK: crj    %r1, %r2, 15, foo                 # encoding: [0xec,0x12,A,A,0xf0,0x76]
+#CHECK:  fixup A - offset: 2, value: foo+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 15, foo
+
+#CHECK: crj    %r1, %r2, 0, bar+100              # encoding: [0xec,0x12,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 0, bar+100
+
+#CHECK: crjh   %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x20,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjh    %r1, %r2, bar+100
+
+#CHECK: crjnle %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x20,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjnle  %r1, %r2, bar+100
+
+#CHECK: crjl   %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x40,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjl    %r1, %r2, bar+100
+
+#CHECK: crjnhe %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x40,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjnhe  %r1, %r2, bar+100
+
+#CHECK: crjlh  %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x60,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjlh   %r1, %r2, bar+100
+
+#CHECK: crjne  %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x60,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjne   %r1, %r2, bar+100
+
+#CHECK: crje   %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x80,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crje    %r1, %r2, bar+100
+
+#CHECK: crjnlh %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0x80,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjnlh  %r1, %r2, bar+100
+
+#CHECK: crjhe  %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0xa0,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjhe   %r1, %r2, bar+100
+
+#CHECK: crjnl  %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0xa0,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjnl   %r1, %r2, bar+100
+
+#CHECK: crjle  %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0xc0,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjle   %r1, %r2, bar+100
+
+#CHECK: crjnh  %r1, %r2, bar+100                 # encoding: [0xec,0x12,A,A,0xc0,0x76]
+#CHECK:  fixup A - offset: 2, value: (bar+100)+2, kind: FK_390_PC16DBL
+       crjnh   %r1, %r2, bar+100
+
+#CHECK: crj    %r1, %r2, 0, bar@PLT              # encoding: [0xec,0x12,A,A,0x00,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crj     %r1, %r2, 0, bar@PLT
+
+#CHECK: crjh   %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x20,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjh    %r1, %r2, bar@PLT
+
+#CHECK: crjnle %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x20,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjnle  %r1, %r2, bar@PLT
+
+#CHECK: crjl   %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x40,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjl    %r1, %r2, bar@PLT
+
+#CHECK: crjnhe %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x40,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjnhe  %r1, %r2, bar@PLT
+
+#CHECK: crjlh  %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x60,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjlh   %r1, %r2, bar@PLT
+
+#CHECK: crjne  %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x60,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjne   %r1, %r2, bar@PLT
+
+#CHECK: crje   %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x80,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crje    %r1, %r2, bar@PLT
+
+#CHECK: crjnlh %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0x80,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjnlh  %r1, %r2, bar@PLT
+
+#CHECK: crjhe  %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0xa0,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjhe   %r1, %r2, bar@PLT
+
+#CHECK: crjnl  %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0xa0,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjnl   %r1, %r2, bar@PLT
+
+#CHECK: crjle  %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0xc0,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjle   %r1, %r2, bar@PLT
+
+#CHECK: crjnh  %r1, %r2, bar@PLT                 # encoding: [0xec,0x12,A,A,0xc0,0x76]
+#CHECK:  fixup A - offset: 2, value: bar@PLT+2, kind: FK_390_PC16DBL
+       crjnh   %r1, %r2, bar@PLT
+
 #CHECK: crl    %r0, .[[LAB:L.*]]-4294967296 # encoding: [0xc6,0x0d,A,A,A,A]
 #CHECK:  fixup A - offset: 2, value: (.[[LAB]]-4294967296)+2, kind: FK_390_PC32DBL
        crl     %r0, -0x100000000