[SystemZ] Support load-and-trap instructions
authorUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 28 Nov 2016 13:59:22 +0000 (13:59 +0000)
committerUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 28 Nov 2016 13:59:22 +0000 (13:59 +0000)
This adds support for the instructions provided with the
load-and-trap facility.

llvm-svn: 288030

15 files changed:
llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
llvm/lib/Target/SystemZ/SystemZFeatures.td
llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
llvm/lib/Target/SystemZ/SystemZInstrInfo.h
llvm/lib/Target/SystemZ/SystemZInstrInfo.td
llvm/lib/Target/SystemZ/SystemZScheduleZ13.td
llvm/lib/Target/SystemZ/SystemZScheduleZEC12.td
llvm/lib/Target/SystemZ/SystemZSubtarget.cpp
llvm/lib/Target/SystemZ/SystemZSubtarget.h
llvm/test/CodeGen/SystemZ/trap-03.ll [new file with mode: 0644]
llvm/test/CodeGen/SystemZ/trap-04.ll [new file with mode: 0644]
llvm/test/CodeGen/SystemZ/trap-05.ll [new file with mode: 0644]
llvm/test/MC/Disassembler/SystemZ/insns.txt
llvm/test/MC/SystemZ/insn-bad-zEC12.s
llvm/test/MC/SystemZ/insn-good-zEC12.s

index b292b55..6e42e28 100644 (file)
@@ -28,6 +28,7 @@ using namespace llvm;
 #define DEBUG_TYPE "systemz-elim-compare"
 
 STATISTIC(BranchOnCounts, "Number of branch-on-count instructions");
+STATISTIC(LoadAndTraps, "Number of load-and-trap instructions");
 STATISTIC(EliminatedComparisons, "Number of eliminated comparisons");
 STATISTIC(FusedComparisons, "Number of fused compare-and-branch instructions");
 
@@ -73,6 +74,8 @@ private:
   Reference getRegReferences(MachineInstr &MI, unsigned Reg);
   bool convertToBRCT(MachineInstr &MI, MachineInstr &Compare,
                      SmallVectorImpl<MachineInstr *> &CCUsers);
+  bool convertToLoadAndTrap(MachineInstr &MI, MachineInstr &Compare,
+                            SmallVectorImpl<MachineInstr *> &CCUsers);
   bool convertToLoadAndTest(MachineInstr &MI);
   bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare,
                              SmallVectorImpl<MachineInstr *> &CCUsers);
@@ -225,6 +228,48 @@ bool SystemZElimCompare::convertToBRCT(
   return true;
 }
 
+// Compare compares the result of MI against zero.  If MI is a suitable load
+// instruction and if CCUsers is a single conditional trap on zero, eliminate
+// the load and convert the branch to a load-and-trap.  Return true on success.
+bool SystemZElimCompare::convertToLoadAndTrap(
+    MachineInstr &MI, MachineInstr &Compare,
+    SmallVectorImpl<MachineInstr *> &CCUsers) {
+  unsigned LATOpcode = TII->getLoadAndTrap(MI.getOpcode());
+  if (!LATOpcode)
+    return false;
+
+  // Check whether we have a single CondTrap that traps on zero.
+  if (CCUsers.size() != 1)
+    return false;
+  MachineInstr *Branch = CCUsers[0];
+  if (Branch->getOpcode() != SystemZ::CondTrap ||
+      Branch->getOperand(0).getImm() != SystemZ::CCMASK_ICMP ||
+      Branch->getOperand(1).getImm() != SystemZ::CCMASK_CMP_EQ)
+    return false;
+
+  // We already know that there are no references to the register between
+  // MI and Compare.  Make sure that there are also no references between
+  // Compare and Branch.
+  unsigned SrcReg = getCompareSourceReg(Compare);
+  MachineBasicBlock::iterator MBBI = Compare, MBBE = Branch;
+  for (++MBBI; MBBI != MBBE; ++MBBI)
+    if (getRegReferences(*MBBI, SrcReg))
+      return false;
+
+  // The transformation is OK.  Rebuild Branch as a load-and-trap.
+  MachineOperand Target(Branch->getOperand(2));
+  while (Branch->getNumOperands())
+    Branch->RemoveOperand(0);
+  Branch->setDesc(TII->get(LATOpcode));
+  MachineInstrBuilder(*Branch->getParent()->getParent(), Branch)
+      .addOperand(MI.getOperand(0))
+      .addOperand(MI.getOperand(1))
+      .addOperand(MI.getOperand(2))
+      .addOperand(MI.getOperand(3));
+  MI.eraseFromParent();
+  return true;
+}
+
 // If MI is a load instruction, try to convert it into a LOAD AND TEST.
 // Return true on success.
 bool SystemZElimCompare::convertToLoadAndTest(MachineInstr &MI) {
@@ -353,11 +398,17 @@ bool SystemZElimCompare::optimizeCompareZero(
     MachineInstr &MI = *MBBI;
     if (resultTests(MI, SrcReg)) {
       // Try to remove both MI and Compare by converting a branch to BRCT(G).
-      // We don't care in this case whether CC is modified between MI and
-      // Compare.
-      if (!CCRefs.Use && !SrcRefs && convertToBRCT(MI, Compare, CCUsers)) {
-        BranchOnCounts += 1;
-        return true;
+      // or a load-and-trap instruction.  We don't care in this case whether
+      // CC is modified between MI and Compare.
+      if (!CCRefs.Use && !SrcRefs) {
+        if (convertToBRCT(MI, Compare, CCUsers)) {
+          BranchOnCounts += 1;
+          return true;
+        }
+        if (convertToLoadAndTrap(MI, Compare, CCUsers)) {
+          LoadAndTraps += 1;
+          return true;
+        }
       }
       // Try to eliminate Compare by reusing a CC result from MI.
       if ((!CCRefs && convertToLoadAndTest(MI)) ||
index 70c5150..0fb3c55 100644 (file)
@@ -84,6 +84,11 @@ def Arch9NewFeatures : SystemZFeatureList<[
 //
 //===----------------------------------------------------------------------===//
 
+def FeatureLoadAndTrap : SystemZFeature<
+  "load-and-trap", "LoadAndTrap",
+  "Assume that the load-and-trap facility is installed"
+>;
+
 def FeatureMiscellaneousExtensions : SystemZFeature<
   "miscellaneous-extensions", "MiscellaneousExtensions",
   "Assume that the miscellaneous-extensions facility is installed"
@@ -100,6 +105,7 @@ def FeatureTransactionalExecution : SystemZFeature<
 >;
 
 def Arch10NewFeatures : SystemZFeatureList<[
+    FeatureLoadAndTrap,
     FeatureMiscellaneousExtensions,
     FeatureProcessorAssist,
     FeatureTransactionalExecution
index 7b835b0..3565d5f 100644 (file)
@@ -1678,6 +1678,25 @@ unsigned SystemZInstrInfo::getFusedCompare(unsigned Opcode,
   return 0;
 }
 
+unsigned SystemZInstrInfo::getLoadAndTrap(unsigned Opcode) const {
+  if (!STI.hasLoadAndTrap())
+    return 0;
+  switch (Opcode) {
+  case SystemZ::L:
+  case SystemZ::LY:
+    return SystemZ::LAT;
+  case SystemZ::LG:
+    return SystemZ::LGAT;
+  case SystemZ::LFH:
+    return SystemZ::LFHAT;
+  case SystemZ::LLGF:
+    return SystemZ::LLGFAT;
+  case SystemZ::LLGT:
+    return SystemZ::LLGTAT;
+  }
+  return 0;
+}
+
 void SystemZInstrInfo::loadImmediate(MachineBasicBlock &MBB,
                                      MachineBasicBlock::iterator MBBI,
                                      unsigned Reg, uint64_t Value) const {
index aadeb6b..794b193 100644 (file)
@@ -286,6 +286,10 @@ public:
                            SystemZII::FusedCompareType Type,
                            const MachineInstr *MI = nullptr) const;
 
+  // If Opcode is a LOAD opcode for with an associated LOAD AND TRAP
+  // operation exists, returh the opcode for the latter, otherwise return 0.
+  unsigned getLoadAndTrap(unsigned Opcode) const;
+
   // Emit code before MBBI in MI to move immediate value Value into
   // physical register Reg.
   void loadImmediate(MachineBasicBlock &MBB,
index 87a70da..c180d40 100644 (file)
@@ -426,6 +426,13 @@ let Predicates = [FeatureLoadAndZeroRightmostByte] in {
             (LZRG bdxaddr20only:$src)>;
 }
 
+// Load and trap.
+let Predicates = [FeatureLoadAndTrap] in {
+  def LAT   : UnaryRXY<"lat",   0xE39F, null_frag, GR32, 4>;
+  def LFHAT : UnaryRXY<"lfhat", 0xE3C8, null_frag, GRH32, 4>;
+  def LGAT  : UnaryRXY<"lgat",  0xE385, null_frag, GR64, 8>;
+}
+
 // Register stores.
 let SimpleBDXStore = 1 in {
   // Expands to ST, STY or STFH, depending on the choice of register.
@@ -662,6 +669,12 @@ let Predicates = [FeatureLoadAndZeroRightmostByte] in {
             (LLZRGF bdxaddr20only:$src)>;
 }
 
+// Load and trap.
+let Predicates = [FeatureLoadAndTrap] in {
+  def LLGFAT : UnaryRXY<"llgfat", 0xE39D, null_frag, GR64, 4>;
+  def LLGTAT : UnaryRXY<"llgtat", 0xE39C, null_frag, GR64, 4>;
+}
+
 //===----------------------------------------------------------------------===//
 // Truncations
 //===----------------------------------------------------------------------===//
index c9007e5..f712d2b 100644 (file)
@@ -202,6 +202,9 @@ def : InstRW<[FXa], (instregex "LR(Mux)?$")>;
 // Load and zero rightmost byte
 def : InstRW<[LSU], (instregex "LZR(F|G)$")>;
 
+// Load and trap
+def : InstRW<[FXb, LSU, Lat5], (instregex "L(FH|G)?AT$")>;
+
 // Load and test
 def : InstRW<[FXa, LSU, Lat5], (instregex "LT(G)?$")>;
 def : InstRW<[FXa], (instregex "LT(G)?R$")>;
@@ -256,6 +259,9 @@ def : InstRW<[LSU], (instregex "LLG(C|H|F|T|HRL|FRL)$")>;
 // Load and zero rightmost byte
 def : InstRW<[LSU], (instregex "LLZRGF$")>;
 
+// Load and trap
+def : InstRW<[FXb, LSU, Lat5], (instregex "LLG(F|T)?AT$")>;
+
 //===----------------------------------------------------------------------===//
 // Truncations
 //===----------------------------------------------------------------------===//
index 7300874..49353eb 100644 (file)
@@ -175,6 +175,9 @@ def : InstRW<[FXU], (instregex "LG(F|H)I$")>;
 def : InstRW<[FXU], (instregex "LHI(Mux)?$")>;
 def : InstRW<[FXU], (instregex "LR(Mux)?$")>;
 
+// Load and trap
+def : InstRW<[FXU, LSU, Lat5], (instregex "L(FH|G)?AT$")>;
+
 // Load and test
 def : InstRW<[FXU, LSU, Lat5], (instregex "LT(G)?$")>;
 def : InstRW<[FXU], (instregex "LT(G)?R$")>;
@@ -224,6 +227,9 @@ def : InstRW<[FXU, LSU, Lat5], (instregex "LL(C|H)H$")>;
 def : InstRW<[LSU], (instregex "LLHRL$")>;
 def : InstRW<[LSU], (instregex "LLG(C|H|F|T|HRL|FRL)$")>;
 
+// Load and trap
+def : InstRW<[FXU, LSU, Lat5], (instregex "LLG(F|T)?AT$")>;
+
 //===----------------------------------------------------------------------===//
 // Truncations
 //===----------------------------------------------------------------------===//
index c749132..bf7277a 100644 (file)
@@ -39,8 +39,8 @@ SystemZSubtarget::SystemZSubtarget(const Triple &TT, const std::string &CPU,
       HasLoadStoreOnCond(false), HasHighWord(false), HasFPExtension(false),
       HasPopulationCount(false), HasFastSerialization(false),
       HasInterlockedAccess1(false), HasMiscellaneousExtensions(false),
-      HasTransactionalExecution(false), HasProcessorAssist(false),
-      HasVector(false), HasLoadStoreOnCond2(false),
+      HasLoadAndTrap(false), HasTransactionalExecution(false),
+      HasProcessorAssist(false), HasVector(false), HasLoadStoreOnCond2(false),
       HasLoadAndZeroRightmostByte(false),
       TargetTriple(TT), InstrInfo(initializeSubtargetDependencies(CPU, FS)),
       TLInfo(TM, *this), TSInfo(), FrameLowering() {}
index 9218a78..8475e2e 100644 (file)
@@ -42,6 +42,7 @@ protected:
   bool HasFastSerialization;
   bool HasInterlockedAccess1;
   bool HasMiscellaneousExtensions;
+  bool HasLoadAndTrap;
   bool HasTransactionalExecution;
   bool HasProcessorAssist;
   bool HasVector;
@@ -113,6 +114,9 @@ public:
     return HasMiscellaneousExtensions;
   }
 
+  // Return true if the target has the load-and-trap facility.
+  bool hasLoadAndTrap() const { return HasLoadAndTrap; }
+
   // Return true if the target has the transactional-execution facility.
   bool hasTransactionalExecution() const { return HasTransactionalExecution; }
 
diff --git a/llvm/test/CodeGen/SystemZ/trap-03.ll b/llvm/test/CodeGen/SystemZ/trap-03.ll
new file mode 100644 (file)
index 0000000..d3cc882
--- /dev/null
@@ -0,0 +1,157 @@
+; Test load-and-trap instructions (LAT/LGAT)
+;
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=zEC12 | FileCheck %s
+
+declare void @llvm.trap()
+
+; Check LAT with no displacement.
+define i32 @f1(i32 *%ptr) {
+; CHECK-LABEL: f1:
+; CHECK: lat %r2, 0(%r2)
+; CHECK: br %r14
+entry:
+  %val = load i32, i32 *%ptr
+  %cmp = icmp eq i32 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i32 %val
+}
+
+; Check the high end of the LAT range.
+define i32 @f2(i32 *%src) {
+; CHECK-LABEL: f2:
+; CHECK: lat %r2, 524284(%r2)
+; CHECK: br %r14
+  %ptr = getelementptr i32, i32 *%src, i64 131071
+  %val = load i32, i32 *%ptr
+  %cmp = icmp eq i32 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i32 %val
+}
+
+; Check the next word up, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define i32 @f3(i32 *%src) {
+; CHECK-LABEL: f3:
+; CHECK: agfi %r2, 524288
+; CHECK: lat %r2, 0(%r2)
+; CHECK: br %r14
+  %ptr = getelementptr i32, i32 *%src, i64 131072
+  %val = load i32, i32 *%ptr
+  %cmp = icmp eq i32 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i32 %val
+}
+
+; Check that LAT allows an index.
+define i32 @f4(i64 %src, i64 %index) {
+; CHECK-LABEL: f4:
+; CHECK: lat %r2, 524287(%r3,%r2)
+; CHECK: br %r14
+  %add1 = add i64 %src, %index
+  %add2 = add i64 %add1, 524287
+  %ptr = inttoptr i64 %add2 to i32 *
+  %val = load i32, i32 *%ptr
+  %cmp = icmp eq i32 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i32 %val
+}
+
+; Check LGAT with no displacement.
+define i64 @f5(i64 *%ptr) {
+; CHECK-LABEL: f5:
+; CHECK: lgat %r2, 0(%r2)
+; CHECK: br %r14
+entry:
+  %val = load i64, i64 *%ptr
+  %cmp = icmp eq i64 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %val
+}
+
+; Check the high end of the LGAT range.
+define i64 @f6(i64 *%src) {
+; CHECK-LABEL: f6:
+; CHECK: lgat %r2, 524280(%r2)
+; CHECK: br %r14
+  %ptr = getelementptr i64, i64 *%src, i64 65535
+  %val = load i64, i64 *%ptr
+  %cmp = icmp eq i64 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %val
+}
+
+; Check the next word up, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define i64 @f7(i64 *%src) {
+; CHECK-LABEL: f7:
+; CHECK: agfi %r2, 524288
+; CHECK: lgat %r2, 0(%r2)
+; CHECK: br %r14
+  %ptr = getelementptr i64, i64 *%src, i64 65536
+  %val = load i64, i64 *%ptr
+  %cmp = icmp eq i64 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %val
+}
+
+; Check that LGAT allows an index.
+define i64 @f8(i64 %src, i64 %index) {
+; CHECK-LABEL: f8:
+; CHECK: lgat %r2, 524287(%r3,%r2)
+; CHECK: br %r14
+  %add1 = add i64 %src, %index
+  %add2 = add i64 %add1, 524287
+  %ptr = inttoptr i64 %add2 to i64 *
+  %val = load i64, i64 *%ptr
+  %cmp = icmp eq i64 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %val
+}
diff --git a/llvm/test/CodeGen/SystemZ/trap-04.ll b/llvm/test/CodeGen/SystemZ/trap-04.ll
new file mode 100644 (file)
index 0000000..9e7897e
--- /dev/null
@@ -0,0 +1,170 @@
+; Test load-and-trap instructions (LLGFAT/LLGFTAT)
+;
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=zEC12 | FileCheck %s
+
+declare void @llvm.trap()
+
+; Check LLGFAT with no displacement.
+define i64 @f1(i32 *%ptr) {
+; CHECK-LABEL: f1:
+; CHECK: llgfat %r2, 0(%r2)
+; CHECK: br %r14
+entry:
+  %val = load i32, i32 *%ptr
+  %ext = zext i32 %val to i64
+  %cmp = icmp eq i64 %ext, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %ext
+}
+
+; Check the high end of the LLGFAT range.
+define i64 @f2(i32 *%src) {
+; CHECK-LABEL: f2:
+; CHECK: llgfat %r2, 524284(%r2)
+; CHECK: br %r14
+  %ptr = getelementptr i32, i32 *%src, i64 131071
+  %val = load i32, i32 *%ptr
+  %ext = zext i32 %val to i64
+  %cmp = icmp eq i64 %ext, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %ext
+}
+
+; Check the next word up, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define i64 @f3(i32 *%src) {
+; CHECK-LABEL: f3:
+; CHECK: agfi %r2, 524288
+; CHECK: llgfat %r2, 0(%r2)
+; CHECK: br %r14
+  %ptr = getelementptr i32, i32 *%src, i64 131072
+  %val = load i32, i32 *%ptr
+  %ext = zext i32 %val to i64
+  %cmp = icmp eq i64 %ext, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %ext
+}
+
+; Check that LLGFAT allows an index.
+define i64 @f4(i64 %src, i64 %index) {
+; CHECK-LABEL: f4:
+; CHECK: llgfat %r2, 524287(%r3,%r2)
+; CHECK: br %r14
+  %add1 = add i64 %src, %index
+  %add2 = add i64 %add1, 524287
+  %ptr = inttoptr i64 %add2 to i32 *
+  %val = load i32, i32 *%ptr
+  %ext = zext i32 %val to i64
+  %cmp = icmp eq i64 %ext, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %ext
+}
+
+; Check LLGTAT with no displacement.
+define i64 @f5(i32 *%ptr) {
+; CHECK-LABEL: f5:
+; CHECK: llgtat %r2, 0(%r2)
+; CHECK: br %r14
+entry:
+  %val = load i32, i32 *%ptr
+  %ext = zext i32 %val to i64
+  %and = and i64 %ext, 2147483647
+  %cmp = icmp eq i64 %and, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %and
+}
+
+; Check the high end of the LLGTAT range.
+define i64 @f6(i32 *%src) {
+; CHECK-LABEL: f6:
+; CHECK: llgtat %r2, 524284(%r2)
+; CHECK: br %r14
+  %ptr = getelementptr i32, i32 *%src, i64 131071
+  %val = load i32, i32 *%ptr
+  %ext = zext i32 %val to i64
+  %and = and i64 %ext, 2147483647
+  %cmp = icmp eq i64 %and, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %and
+}
+
+; Check the next word up, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define i64 @f7(i32 *%src) {
+; CHECK-LABEL: f7:
+; CHECK: agfi %r2, 524288
+; CHECK: llgtat %r2, 0(%r2)
+; CHECK: br %r14
+  %ptr = getelementptr i32, i32 *%src, i64 131072
+  %val = load i32, i32 *%ptr
+  %ext = zext i32 %val to i64
+  %and = and i64 %ext, 2147483647
+  %cmp = icmp eq i64 %and, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %and
+}
+
+; Check that LLGTAT allows an index.
+define i64 @f8(i64 %src, i64 %index) {
+; CHECK-LABEL: f8:
+; CHECK: llgtat %r2, 524287(%r3,%r2)
+; CHECK: br %r14
+  %add1 = add i64 %src, %index
+  %add2 = add i64 %add1, 524287
+  %ptr = inttoptr i64 %add2 to i32 *
+  %val = load i32, i32 *%ptr
+  %ext = zext i32 %val to i64
+  %and = and i64 %ext, 2147483647
+  %cmp = icmp eq i64 %and, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  ret i64 %and
+}
+
diff --git a/llvm/test/CodeGen/SystemZ/trap-05.ll b/llvm/test/CodeGen/SystemZ/trap-05.ll
new file mode 100644 (file)
index 0000000..7aabedb
--- /dev/null
@@ -0,0 +1,92 @@
+; Test load-and-trap instructions (LFHAT)
+; See comments in asm-18.ll about testing high-word operations.
+;
+; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=zEC12 \
+; RUN:   -no-integrated-as | FileCheck %s
+
+declare void @llvm.trap()
+
+; Check LAT with no displacement.
+define void @f1(i32 *%ptr) {
+; CHECK-LABEL: f1:
+; CHECK: lfhat [[REG:%r[0-9]+]], 0(%r2)
+; CHECK: stepa [[REG]]
+; CHECK: br %r14
+entry:
+  %val = load i32, i32 *%ptr
+  %cmp = icmp eq i32 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  call void asm sideeffect "stepa $0", "h"(i32 %val)
+  ret void;
+}
+
+; Check the high end of the LAT range.
+define void @f2(i32 *%src) {
+; CHECK-LABEL: f2:
+; CHECK: lfhat [[REG:%r[0-9]+]], 524284(%r2)
+; CHECK: stepa [[REG]]
+; CHECK: br %r14
+  %ptr = getelementptr i32, i32 *%src, i64 131071
+  %val = load i32, i32 *%ptr
+  %cmp = icmp eq i32 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  call void asm sideeffect "stepa $0", "h"(i32 %val)
+  ret void;
+}
+
+; Check the next word up, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f3(i32 *%src) {
+; CHECK-LABEL: f3:
+; CHECK: agfi %r2, 524288
+; CHECK: lfhat [[REG:%r[0-9]+]], 0(%r2)
+; CHECK: stepa [[REG]]
+; CHECK: br %r14
+  %ptr = getelementptr i32, i32 *%src, i64 131072
+  %val = load i32, i32 *%ptr
+  %cmp = icmp eq i32 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  call void asm sideeffect "stepa $0", "h"(i32 %val)
+  ret void;
+}
+
+; Check that LAT allows an index.
+define void @f4(i64 %src, i64 %index) {
+; CHECK-LABEL: f4:
+; CHECK: lfhat [[REG:%r[0-9]+]], 524287(%r3,%r2)
+; CHECK: stepa [[REG]]
+; CHECK: br %r14
+  %add1 = add i64 %src, %index
+  %add2 = add i64 %add1, 524287
+  %ptr = inttoptr i64 %add2 to i32 *
+  %val = load i32, i32 *%ptr
+  %cmp = icmp eq i32 %val, 0
+  br i1 %cmp, label %if.then, label %if.end
+
+if.then:                                          ; preds = %entry
+  tail call void @llvm.trap()
+  unreachable
+
+if.end:                                           ; preds = %entry
+  call void asm sideeffect "stepa $0", "h"(i32 %val)
+  ret void;
+}
+
index 1c521a5..b19281a 100644 (file)
 # CHECK: lfh %r15, 0
 0xe3 0xf0 0x00 0x00 0x00 0xca
 
+# CHECK: lfhat %r0, -524288
+0xe3 0x00 0x00 0x00 0x80 0xc8
+
+# CHECK: lfhat %r0, -1
+0xe3 0x00 0x0f 0xff 0xff 0xc8
+
+# CHECK: lfhat %r0, 0
+0xe3 0x00 0x00 0x00 0x00 0xc8
+
+# CHECK: lfhat %r0, 1
+0xe3 0x00 0x00 0x01 0x00 0xc8
+
+# CHECK: lfhat %r0, 524287
+0xe3 0x00 0x0f 0xff 0x7f 0xc8
+
+# CHECK: lfhat %r0, 0(%r1)
+0xe3 0x00 0x10 0x00 0x00 0xc8
+
+# CHECK: lfhat %r0, 0(%r15)
+0xe3 0x00 0xf0 0x00 0x00 0xc8
+
+# CHECK: lfhat %r0, 524287(%r1,%r15)
+0xe3 0x01 0xff 0xff 0x7f 0xc8
+
+# CHECK: lfhat %r0, 524287(%r15,%r1)
+0xe3 0x0f 0x1f 0xff 0x7f 0xc8
+
+# CHECK: lfhat %r15, 0
+0xe3 0xf0 0x00 0x00 0x00 0xc8
+
 # CHECK: lgbr %r0, %r15
 0xb9 0x06 0x00 0x0f
 
 # CHECK: lg %r15, 0
 0xe3 0xf0 0x00 0x00 0x00 0x04
 
+# CHECK: lgat %r0, -524288
+0xe3 0x00 0x00 0x00 0x80 0x85
+
+# CHECK: lgat %r0, -1
+0xe3 0x00 0x0f 0xff 0xff 0x85
+
+# CHECK: lgat %r0, 0
+0xe3 0x00 0x00 0x00 0x00 0x85
+
+# CHECK: lgat %r0, 1
+0xe3 0x00 0x00 0x01 0x00 0x85
+
+# CHECK: lgat %r0, 524287
+0xe3 0x00 0x0f 0xff 0x7f 0x85
+
+# CHECK: lgat %r0, 0(%r1)
+0xe3 0x00 0x10 0x00 0x00 0x85
+
+# CHECK: lgat %r0, 0(%r15)
+0xe3 0x00 0xf0 0x00 0x00 0x85
+
+# CHECK: lgat %r0, 524287(%r1,%r15)
+0xe3 0x01 0xff 0xff 0x7f 0x85
+
+# CHECK: lgat %r0, 524287(%r15,%r1)
+0xe3 0x0f 0x1f 0xff 0x7f 0x85
+
+# CHECK: lgat %r15, 0
+0xe3 0xf0 0x00 0x00 0x00 0x85
+
 # CHECK: lhi %r0, -32768
 0xa7 0x08 0x80 0x00
 
 # CHECK: llgf %r15, 0
 0xe3 0xf0 0x00 0x00 0x00 0x16
 
+# CHECK: llgfat %r0, -524288
+0xe3 0x00 0x00 0x00 0x80 0x9d
+
+# CHECK: llgfat %r0, -1
+0xe3 0x00 0x0f 0xff 0xff 0x9d
+
+# CHECK: llgfat %r0, 0
+0xe3 0x00 0x00 0x00 0x00 0x9d
+
+# CHECK: llgfat %r0, 1
+0xe3 0x00 0x00 0x01 0x00 0x9d
+
+# CHECK: llgfat %r0, 524287
+0xe3 0x00 0x0f 0xff 0x7f 0x9d
+
+# CHECK: llgfat %r0, 0(%r1)
+0xe3 0x00 0x10 0x00 0x00 0x9d
+
+# CHECK: llgfat %r0, 0(%r15)
+0xe3 0x00 0xf0 0x00 0x00 0x9d
+
+# CHECK: llgfat %r0, 524287(%r1,%r15)
+0xe3 0x01 0xff 0xff 0x7f 0x9d
+
+# CHECK: llgfat %r0, 524287(%r15,%r1)
+0xe3 0x0f 0x1f 0xff 0x7f 0x9d
+
+# CHECK: llgfat %r15, 0
+0xe3 0xf0 0x00 0x00 0x00 0x9d
+
 # CHECK: llgtr %r0, %r15
 0xb9 0x17 0x00 0x0f
 
 # CHECK: llgt %r15, 0
 0xe3 0xf0 0x00 0x00 0x00 0x17
 
+# CHECK: llgtat %r0, -524288
+0xe3 0x00 0x00 0x00 0x80 0x9c
+
+# CHECK: llgtat %r0, -1
+0xe3 0x00 0x0f 0xff 0xff 0x9c
+
+# CHECK: llgtat %r0, 0
+0xe3 0x00 0x00 0x00 0x00 0x9c
+
+# CHECK: llgtat %r0, 1
+0xe3 0x00 0x00 0x01 0x00 0x9c
+
+# CHECK: llgtat %r0, 524287
+0xe3 0x00 0x0f 0xff 0x7f 0x9c
+
+# CHECK: llgtat %r0, 0(%r1)
+0xe3 0x00 0x10 0x00 0x00 0x9c
+
+# CHECK: llgtat %r0, 0(%r15)
+0xe3 0x00 0xf0 0x00 0x00 0x9c
+
+# CHECK: llgtat %r0, 524287(%r1,%r15)
+0xe3 0x01 0xff 0xff 0x7f 0x9c
+
+# CHECK: llgtat %r0, 524287(%r15,%r1)
+0xe3 0x0f 0x1f 0xff 0x7f 0x9c
+
+# CHECK: llgtat %r15, 0
+0xe3 0xf0 0x00 0x00 0x00 0x9c
+
 # CHECK: llghr %r0, %r15
 0xb9 0x85 0x00 0x0f
 
 # CHECK: l %r15, 0
 0x58 0xf0 0x00 0x00
 
+# CHECK: lat %r0, -524288
+0xe3 0x00 0x00 0x00 0x80 0x9f
+
+# CHECK: lat %r0, -1
+0xe3 0x00 0x0f 0xff 0xff 0x9f
+
+# CHECK: lat %r0, 0
+0xe3 0x00 0x00 0x00 0x00 0x9f
+
+# CHECK: lat %r0, 1
+0xe3 0x00 0x00 0x01 0x00 0x9f
+
+# CHECK: lat %r0, 524287
+0xe3 0x00 0x0f 0xff 0x7f 0x9f
+
+# CHECK: lat %r0, 0(%r1)
+0xe3 0x00 0x10 0x00 0x00 0x9f
+
+# CHECK: lat %r0, 0(%r15)
+0xe3 0x00 0xf0 0x00 0x00 0x9f
+
+# CHECK: lat %r0, 524287(%r1,%r15)
+0xe3 0x01 0xff 0xff 0x7f 0x9f
+
+# CHECK: lat %r0, 524287(%r15,%r1)
+0xe3 0x0f 0x1f 0xff 0x7f 0x9f
+
+# CHECK: lat %r15, 0
+0xe3 0xf0 0x00 0x00 0x00 0x9f
+
 # CHECK: lt %r0, -524288
 0xe3 0x00 0x00 0x00 0x80 0x12
 
index b86b4b8..a88fe7e 100644 (file)
         clgto    %r0, 0
         clgtno   %r0, 0
 
+#CHECK: error: invalid operand
+#CHECK: lat    %r0, -524289
+#CHECK: error: invalid operand
+#CHECK: lat    %r0, 524288
+
+       lat     %r0, -524289
+       lat     %r0, 524288
+
+#CHECK: error: invalid operand
+#CHECK: lfhat  %r0, -524289
+#CHECK: error: invalid operand
+#CHECK: lfhat  %r0, 524288
+
+       lfhat   %r0, -524289
+       lfhat   %r0, 524288
+
+#CHECK: error: invalid operand
+#CHECK: lgat   %r0, -524289
+#CHECK: error: invalid operand
+#CHECK: lgat   %r0, 524288
+
+       lgat    %r0, -524289
+       lgat    %r0, 524288
+
+#CHECK: error: invalid operand
+#CHECK: llgfat %r0, -524289
+#CHECK: error: invalid operand
+#CHECK: llgfat %r0, 524288
+
+       llgfat  %r0, -524289
+       llgfat  %r0, 524288
+
+#CHECK: error: invalid operand
+#CHECK: llgtat %r0, -524289
+#CHECK: error: invalid operand
+#CHECK: llgtat %r0, 524288
+
+       llgtat  %r0, -524289
+       llgtat  %r0, 524288
+
 #CHECK: error: instruction requires: vector
 #CHECK: lcbb   %r0, 0, 0
 
index b58ce70..cb604f9 100644 (file)
        clgtnl  %r0, 0(%r15)
        clgtnh  %r0, 0(%r15)
 
+#CHECK: lat    %r0, -524288            # encoding: [0xe3,0x00,0x00,0x00,0x80,0x9f]
+#CHECK: lat    %r0, -1                 # encoding: [0xe3,0x00,0x0f,0xff,0xff,0x9f]
+#CHECK: lat    %r0, 0                  # encoding: [0xe3,0x00,0x00,0x00,0x00,0x9f]
+#CHECK: lat    %r0, 1                  # encoding: [0xe3,0x00,0x00,0x01,0x00,0x9f]
+#CHECK: lat    %r0, 524287             # encoding: [0xe3,0x00,0x0f,0xff,0x7f,0x9f]
+#CHECK: lat    %r0, 0(%r1)             # encoding: [0xe3,0x00,0x10,0x00,0x00,0x9f]
+#CHECK: lat    %r0, 0(%r15)            # encoding: [0xe3,0x00,0xf0,0x00,0x00,0x9f]
+#CHECK: lat    %r0, 524287(%r1,%r15)   # encoding: [0xe3,0x01,0xff,0xff,0x7f,0x9f]
+#CHECK: lat    %r0, 524287(%r15,%r1)   # encoding: [0xe3,0x0f,0x1f,0xff,0x7f,0x9f]
+#CHECK: lat    %r15, 0                 # encoding: [0xe3,0xf0,0x00,0x00,0x00,0x9f]
+
+       lat     %r0, -524288
+       lat     %r0, -1
+       lat     %r0, 0
+       lat     %r0, 1
+       lat     %r0, 524287
+       lat     %r0, 0(%r1)
+       lat     %r0, 0(%r15)
+       lat     %r0, 524287(%r1,%r15)
+       lat     %r0, 524287(%r15,%r1)
+       lat     %r15, 0
+
+#CHECK: lfhat  %r0, -524288            # encoding: [0xe3,0x00,0x00,0x00,0x80,0xc8]
+#CHECK: lfhat  %r0, -1                 # encoding: [0xe3,0x00,0x0f,0xff,0xff,0xc8]
+#CHECK: lfhat  %r0, 0                  # encoding: [0xe3,0x00,0x00,0x00,0x00,0xc8]
+#CHECK: lfhat  %r0, 1                  # encoding: [0xe3,0x00,0x00,0x01,0x00,0xc8]
+#CHECK: lfhat  %r0, 524287             # encoding: [0xe3,0x00,0x0f,0xff,0x7f,0xc8]
+#CHECK: lfhat  %r0, 0(%r1)             # encoding: [0xe3,0x00,0x10,0x00,0x00,0xc8]
+#CHECK: lfhat  %r0, 0(%r15)            # encoding: [0xe3,0x00,0xf0,0x00,0x00,0xc8]
+#CHECK: lfhat  %r0, 524287(%r1,%r15)   # encoding: [0xe3,0x01,0xff,0xff,0x7f,0xc8]
+#CHECK: lfhat  %r0, 524287(%r15,%r1)   # encoding: [0xe3,0x0f,0x1f,0xff,0x7f,0xc8]
+#CHECK: lfhat  %r15, 0                 # encoding: [0xe3,0xf0,0x00,0x00,0x00,0xc8]
+
+       lfhat   %r0, -524288
+       lfhat   %r0, -1
+       lfhat   %r0, 0
+       lfhat   %r0, 1
+       lfhat   %r0, 524287
+       lfhat   %r0, 0(%r1)
+       lfhat   %r0, 0(%r15)
+       lfhat   %r0, 524287(%r1,%r15)
+       lfhat   %r0, 524287(%r15,%r1)
+       lfhat   %r15, 0
+
+#CHECK: lgat   %r0, -524288            # encoding: [0xe3,0x00,0x00,0x00,0x80,0x85]
+#CHECK: lgat   %r0, -1                 # encoding: [0xe3,0x00,0x0f,0xff,0xff,0x85]
+#CHECK: lgat   %r0, 0                  # encoding: [0xe3,0x00,0x00,0x00,0x00,0x85]
+#CHECK: lgat   %r0, 1                  # encoding: [0xe3,0x00,0x00,0x01,0x00,0x85]
+#CHECK: lgat   %r0, 524287             # encoding: [0xe3,0x00,0x0f,0xff,0x7f,0x85]
+#CHECK: lgat   %r0, 0(%r1)             # encoding: [0xe3,0x00,0x10,0x00,0x00,0x85]
+#CHECK: lgat   %r0, 0(%r15)            # encoding: [0xe3,0x00,0xf0,0x00,0x00,0x85]
+#CHECK: lgat   %r0, 524287(%r1,%r15)   # encoding: [0xe3,0x01,0xff,0xff,0x7f,0x85]
+#CHECK: lgat   %r0, 524287(%r15,%r1)   # encoding: [0xe3,0x0f,0x1f,0xff,0x7f,0x85]
+#CHECK: lgat   %r15, 0                 # encoding: [0xe3,0xf0,0x00,0x00,0x00,0x85]
+
+       lgat    %r0, -524288
+       lgat    %r0, -1
+       lgat    %r0, 0
+       lgat    %r0, 1
+       lgat    %r0, 524287
+       lgat    %r0, 0(%r1)
+       lgat    %r0, 0(%r15)
+       lgat    %r0, 524287(%r1,%r15)
+       lgat    %r0, 524287(%r15,%r1)
+       lgat    %r15, 0
+
+#CHECK: llgfat %r0, -524288            # encoding: [0xe3,0x00,0x00,0x00,0x80,0x9d]
+#CHECK: llgfat %r0, -1                 # encoding: [0xe3,0x00,0x0f,0xff,0xff,0x9d]
+#CHECK: llgfat %r0, 0                  # encoding: [0xe3,0x00,0x00,0x00,0x00,0x9d]
+#CHECK: llgfat %r0, 1                  # encoding: [0xe3,0x00,0x00,0x01,0x00,0x9d]
+#CHECK: llgfat %r0, 524287             # encoding: [0xe3,0x00,0x0f,0xff,0x7f,0x9d]
+#CHECK: llgfat %r0, 0(%r1)             # encoding: [0xe3,0x00,0x10,0x00,0x00,0x9d]
+#CHECK: llgfat %r0, 0(%r15)            # encoding: [0xe3,0x00,0xf0,0x00,0x00,0x9d]
+#CHECK: llgfat %r0, 524287(%r1,%r15)   # encoding: [0xe3,0x01,0xff,0xff,0x7f,0x9d]
+#CHECK: llgfat %r0, 524287(%r15,%r1)   # encoding: [0xe3,0x0f,0x1f,0xff,0x7f,0x9d]
+#CHECK: llgfat %r15, 0                 # encoding: [0xe3,0xf0,0x00,0x00,0x00,0x9d]
+
+       llgfat  %r0, -524288
+       llgfat  %r0, -1
+       llgfat  %r0, 0
+       llgfat  %r0, 1
+       llgfat  %r0, 524287
+       llgfat  %r0, 0(%r1)
+       llgfat  %r0, 0(%r15)
+       llgfat  %r0, 524287(%r1,%r15)
+       llgfat  %r0, 524287(%r15,%r1)
+       llgfat  %r15, 0
+
+#CHECK: llgtat %r0, -524288            # encoding: [0xe3,0x00,0x00,0x00,0x80,0x9c]
+#CHECK: llgtat %r0, -1                 # encoding: [0xe3,0x00,0x0f,0xff,0xff,0x9c]
+#CHECK: llgtat %r0, 0                  # encoding: [0xe3,0x00,0x00,0x00,0x00,0x9c]
+#CHECK: llgtat %r0, 1                  # encoding: [0xe3,0x00,0x00,0x01,0x00,0x9c]
+#CHECK: llgtat %r0, 524287             # encoding: [0xe3,0x00,0x0f,0xff,0x7f,0x9c]
+#CHECK: llgtat %r0, 0(%r1)             # encoding: [0xe3,0x00,0x10,0x00,0x00,0x9c]
+#CHECK: llgtat %r0, 0(%r15)            # encoding: [0xe3,0x00,0xf0,0x00,0x00,0x9c]
+#CHECK: llgtat %r0, 524287(%r1,%r15)   # encoding: [0xe3,0x01,0xff,0xff,0x7f,0x9c]
+#CHECK: llgtat %r0, 524287(%r15,%r1)   # encoding: [0xe3,0x0f,0x1f,0xff,0x7f,0x9c]
+#CHECK: llgtat %r15, 0                 # encoding: [0xe3,0xf0,0x00,0x00,0x00,0x9c]
+
+       llgtat  %r0, -524288
+       llgtat  %r0, -1
+       llgtat  %r0, 0
+       llgtat  %r0, 1
+       llgtat  %r0, 524287
+       llgtat  %r0, 0(%r1)
+       llgtat  %r0, 0(%r15)
+       llgtat  %r0, 524287(%r1,%r15)
+       llgtat  %r0, 524287(%r15,%r1)
+       llgtat  %r15, 0
+
 #CHECK: etnd   %r0                     # encoding: [0xb2,0xec,0x00,0x00]
 #CHECK: etnd   %r15                    # encoding: [0xb2,0xec,0x00,0xf0]
 #CHECK: etnd   %r7                     # encoding: [0xb2,0xec,0x00,0x70]