From 16277c4698f36a756c540fae326874774156aaed Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Thu, 5 Sep 2013 10:36:45 +0000 Subject: [PATCH] [SystemZ] Add NC, OC and XC For now these are just used to handle scalar ANDs, ORs and XORs in which all operands are memory. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190041 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/SystemZ/SystemZISelDAGToDAG.cpp | 71 ++-- lib/Target/SystemZ/SystemZISelLowering.cpp | 15 + lib/Target/SystemZ/SystemZISelLowering.h | 8 + lib/Target/SystemZ/SystemZInstrFP.td | 6 +- lib/Target/SystemZ/SystemZInstrInfo.td | 42 ++- lib/Target/SystemZ/SystemZOperators.td | 37 ++ lib/Target/SystemZ/SystemZPatterns.td | 41 ++- test/CodeGen/SystemZ/and-08.ll | 397 +++++++++++++++++++++ test/CodeGen/SystemZ/or-08.ll | 57 +++ test/CodeGen/SystemZ/xor-08.ll | 57 +++ test/MC/Disassembler/SystemZ/insns.txt | 108 ++++++ test/MC/SystemZ/insn-bad.s | 132 +++++++ test/MC/SystemZ/insn-good.s | 78 ++++ 13 files changed, 1001 insertions(+), 48 deletions(-) create mode 100644 test/CodeGen/SystemZ/and-08.ll create mode 100644 test/CodeGen/SystemZ/or-08.ll create mode 100644 test/CodeGen/SystemZ/xor-08.ll diff --git a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp index e0d543791b0..9d71c3948d6 100644 --- a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -290,8 +290,15 @@ class SystemZDAGToDAGISel : public SelectionDAGISel { SDNode *splitLargeImmediate(unsigned Opcode, SDNode *Node, SDValue Op0, uint64_t UpperVal, uint64_t LowerVal); + // N is a (store (load Y), X) pattern. Return true if it can use an MVC + // from Y to X. bool storeLoadCanUseMVC(SDNode *N) const; + // N is a (store (op (load A[0]), (load A[1])), X) pattern. Return true + // if A[1 - I] == X and if N can use a block operation like NC from A[I] + // to X. + bool storeLoadCanUseBlockBinary(SDNode *N, unsigned I) const; + public: SystemZDAGToDAGISel(SystemZTargetMachine &TM, CodeGenOpt::Level OptLevel) : SelectionDAGISel(TM, OptLevel), @@ -925,34 +932,27 @@ SDNode *SystemZDAGToDAGISel::splitLargeImmediate(unsigned Opcode, SDNode *Node, return Or.getNode(); } -// N is a (store (load ...), ...) pattern. Return true if it can use MVC. -bool SystemZDAGToDAGISel::storeLoadCanUseMVC(SDNode *N) const { - StoreSDNode *Store = cast(N); - LoadSDNode *Load = cast(Store->getValue().getNode()); - - // MVC is logically a bytewise copy, so can't be used for volatile accesses. - if (Load->isVolatile() || Store->isVolatile()) +// Return true if Load and Store: +// - are loads and stores of the same size; +// - do not partially overlap; and +// - can be decomposed into what are logically individual character accesses +// without changing the semantics. +static bool canUseBlockOperation(StoreSDNode *Store, LoadSDNode *Load, + AliasAnalysis *AA) { + // Check that the two memory operands have the same size. + if (Load->getMemoryVT() != Store->getMemoryVT()) return false; - // Prefer not to use MVC if either address can use ... RELATIVE LONG - // instructions. - assert(Load->getMemoryVT() == Store->getMemoryVT() && - "Should already have checked that the types match"); - uint64_t Size = Load->getMemoryVT().getStoreSize(); - if (Size > 1 && Size <= 8) { - // Prefer LHRL, LRL and LGRL. - if (Load->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER) - return false; - // Prefer STHRL, STRL and STGRL. - if (Store->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER) - return false; - } + // Volatility stops an access from being decomposed. + if (Load->isVolatile() || Store->isVolatile()) + return false; // There's no chance of overlap if the load is invariant. if (Load->isInvariant()) return true; // If both operands are aligned, they must be equal or not overlap. + uint64_t Size = Load->getMemoryVT().getStoreSize(); if (Load->getAlignment() >= Size && Store->getAlignment() >= Size) return true; @@ -968,6 +968,37 @@ bool SystemZDAGToDAGISel::storeLoadCanUseMVC(SDNode *N) const { AliasAnalysis::Location(V2, End2, Store->getTBAAInfo())); } +bool SystemZDAGToDAGISel::storeLoadCanUseMVC(SDNode *N) const { + StoreSDNode *Store = cast(N); + LoadSDNode *Load = cast(Store->getValue()); + + // Prefer not to use MVC if either address can use ... RELATIVE LONG + // instructions. + uint64_t Size = Load->getMemoryVT().getStoreSize(); + if (Size > 1 && Size <= 8) { + // Prefer LHRL, LRL and LGRL. + if (Load->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER) + return false; + // Prefer STHRL, STRL and STGRL. + if (Store->getBasePtr().getOpcode() == SystemZISD::PCREL_WRAPPER) + return false; + } + + return canUseBlockOperation(Store, Load, AA); +} + +bool SystemZDAGToDAGISel::storeLoadCanUseBlockBinary(SDNode *N, + unsigned I) const { + StoreSDNode *StoreA = cast(N); + LoadSDNode *LoadA = cast(StoreA->getValue().getOperand(1 - I)); + LoadSDNode *LoadB = cast(StoreA->getValue().getOperand(I)); + if (LoadA->isVolatile() || + LoadA->getMemoryVT() != StoreA->getMemoryVT() || + LoadA->getBasePtr() != StoreA->getBasePtr()) + return false; + return canUseBlockOperation(StoreA, LoadB, AA); +} + SDNode *SystemZDAGToDAGISel::Select(SDNode *Node) { // Dump information about the Node being selected DEBUG(errs() << "Selecting: "; Node->dump(CurDAG); errs() << "\n"); diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp index 13d5604be13..180c631ce13 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -2054,6 +2054,12 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(UDIVREM64); OPCODE(MVC); OPCODE(MVC_LOOP); + OPCODE(NC); + OPCODE(NC_LOOP); + OPCODE(OC); + OPCODE(OC_LOOP); + OPCODE(XC); + OPCODE(XC_LOOP); OPCODE(CLC); OPCODE(CLC_LOOP); OPCODE(STRCMP); @@ -3077,6 +3083,15 @@ EmitInstrWithCustomInserter(MachineInstr *MI, MachineBasicBlock *MBB) const { case SystemZ::MVCSequence: case SystemZ::MVCLoop: return emitMemMemWrapper(MI, MBB, SystemZ::MVC); + case SystemZ::NCSequence: + case SystemZ::NCLoop: + return emitMemMemWrapper(MI, MBB, SystemZ::NC); + case SystemZ::OCSequence: + case SystemZ::OCLoop: + return emitMemMemWrapper(MI, MBB, SystemZ::OC); + case SystemZ::XCSequence: + case SystemZ::XCLoop: + return emitMemMemWrapper(MI, MBB, SystemZ::XC); case SystemZ::CLCSequence: case SystemZ::CLCLoop: return emitMemMemWrapper(MI, MBB, SystemZ::CLC); diff --git a/lib/Target/SystemZ/SystemZISelLowering.h b/lib/Target/SystemZ/SystemZISelLowering.h index ec5051f3e6e..8b2d19a1d2d 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.h +++ b/lib/Target/SystemZ/SystemZISelLowering.h @@ -93,6 +93,14 @@ namespace SystemZISD { // The value of X is passed as an additional operand. MVC_LOOP, + // Similar to MVC and MVC_LOOP, but for logic operations (AND, OR, XOR). + NC, + NC_LOOP, + OC, + OC_LOOP, + XC, + XC_LOOP, + // Use CLC to compare two blocks of memory, with the same comments // as for MVC and MVC_LOOP. CLC, diff --git a/lib/Target/SystemZ/SystemZInstrFP.td b/lib/Target/SystemZ/SystemZInstrFP.td index 8d0dcb673fc..24adaeec0cd 100644 --- a/lib/Target/SystemZ/SystemZInstrFP.td +++ b/lib/Target/SystemZ/SystemZInstrFP.td @@ -86,9 +86,9 @@ def : CopySign128; -defm LoadStoreF32 : MVCLoadStore; -defm LoadStoreF64 : MVCLoadStore; -defm LoadStoreF128 : MVCLoadStore; +defm LoadStoreF32 : MVCLoadStore; +defm LoadStoreF64 : MVCLoadStore; +defm LoadStoreF128 : MVCLoadStore; //===----------------------------------------------------------------------===// // Load instructions diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index 7793818b796..abe28a57ec4 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -350,20 +350,6 @@ let mayLoad = 1, mayStore = 1 in let mayLoad = 1, mayStore = 1, Defs = [CC], Uses = [R0W] in defm MVST : StringRRE<"mvst", 0xB255, z_stpcpy>; -defm LoadStore8_32 : MVCLoadStore; -defm LoadStore16_32 : MVCLoadStore; -defm LoadStore32_32 : MVCLoadStore; - -defm LoadStore8 : MVCLoadStore; -defm LoadStore16 : MVCLoadStore; -defm LoadStore32 : MVCLoadStore; -defm LoadStore64 : MVCLoadStore; - //===----------------------------------------------------------------------===// // Sign extensions //===----------------------------------------------------------------------===// @@ -770,6 +756,10 @@ let Defs = [CC] in { // AND to memory defm NI : BinarySIPair<"ni", 0x94, 0xEB54, null_frag, uimm8>; + + // Block AND. + let mayLoad = 1, mayStore = 1 in + defm NC : MemorySS<"nc", 0xD4, z_nc, z_nc_loop>; } defm : RMWIByte; defm : RMWIByte; @@ -812,6 +802,10 @@ let Defs = [CC] in { // OR to memory defm OI : BinarySIPair<"oi", 0x96, 0xEB56, null_frag, uimm8>; + + // Block OR. + let mayLoad = 1, mayStore = 1 in + defm OC : MemorySS<"oc", 0xD6, z_oc, z_oc_loop>; } defm : RMWIByte; defm : RMWIByte; @@ -843,6 +837,10 @@ let Defs = [CC] in { // XOR to memory defm XI : BinarySIPair<"xi", 0x97, 0xEB57, null_frag, uimm8>; + + // Block XOR. + let mayLoad = 1, mayStore = 1 in + defm XC : MemorySS<"xc", 0xD7, z_xc, z_xc_loop>; } defm : RMWIByte; defm : RMWIByte; @@ -1246,3 +1244,19 @@ def : Pat<(sra (shl (i64 (anyext (i32 (z_select_ccmask 1, 0, uimm8zx4:$valid, (i32 63)), (i32 63)), (Select64 (LGHI -1), (LGHI 0), uimm8zx4:$valid, uimm8zx4:$cc)>; + +// Peepholes for turning scalar operations into block operations. +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; +defm : BlockLoadStore; diff --git a/lib/Target/SystemZ/SystemZOperators.td b/lib/Target/SystemZ/SystemZOperators.td index 822195c02a5..c89e31548b9 100644 --- a/lib/Target/SystemZ/SystemZOperators.td +++ b/lib/Target/SystemZ/SystemZOperators.td @@ -131,6 +131,18 @@ def z_mvc : SDNode<"SystemZISD::MVC", SDT_ZMemMemLength, [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; def z_mvc_loop : SDNode<"SystemZISD::MVC_LOOP", SDT_ZMemMemLoop, [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_nc : SDNode<"SystemZISD::NC", SDT_ZMemMemLength, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_nc_loop : SDNode<"SystemZISD::NC_LOOP", SDT_ZMemMemLoop, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_oc : SDNode<"SystemZISD::OC", SDT_ZMemMemLength, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_oc_loop : SDNode<"SystemZISD::OC_LOOP", SDT_ZMemMemLoop, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_xc : SDNode<"SystemZISD::XC", SDT_ZMemMemLength, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; +def z_xc_loop : SDNode<"SystemZISD::XC_LOOP", SDT_ZMemMemLoop, + [SDNPHasChain, SDNPMayStore, SDNPMayLoad]>; def z_clc : SDNode<"SystemZISD::CLC", SDT_ZMemMemLength, [SDNPHasChain, SDNPOutGlue, SDNPMayLoad]>; def z_clc_loop : SDNode<"SystemZISD::CLC_LOOP", SDT_ZMemMemLoop, @@ -224,6 +236,31 @@ def nonvolatile_truncstorei8 : NonvolatileStore; def nonvolatile_truncstorei16 : NonvolatileStore; def nonvolatile_truncstorei32 : NonvolatileStore; +// A store of a load that can be implemented using MVC. +def mvc_store : PatFrag<(ops node:$value, node:$addr), + (unindexedstore node:$value, node:$addr), + [{ return storeLoadCanUseMVC(N); }]>; + +// Binary read-modify-write operations on memory in which the other +// operand is also memory and for which block operations like NC can +// be used. There are two patterns for each operator, depending on +// which operand contains the "other" load. +multiclass block_op { + def "1" : PatFrag<(ops node:$value, node:$addr), + (unindexedstore (operator node:$value, + (unindexedload node:$addr)), + node:$addr), + [{ return storeLoadCanUseBlockBinary(N, 0); }]>; + def "2" : PatFrag<(ops node:$value, node:$addr), + (unindexedstore (operator (unindexedload node:$addr), + node:$value), + node:$addr), + [{ return storeLoadCanUseBlockBinary(N, 1); }]>; +} +defm block_and : block_op; +defm block_or : block_op; +defm block_xor : block_op; + // Insertions. def inserti8 : PatFrag<(ops node:$src1, node:$src2), (or (and node:$src1, -256), node:$src2)>; diff --git a/lib/Target/SystemZ/SystemZPatterns.td b/lib/Target/SystemZ/SystemZPatterns.td index c442ae0d95d..bc3775f2795 100644 --- a/lib/Target/SystemZ/SystemZPatterns.td +++ b/lib/Target/SystemZ/SystemZPatterns.td @@ -66,20 +66,39 @@ multiclass InsertMem; } -// Use MVC instruction INSN for a load of type LOAD followed by a store -// of type STORE. VT is the type of the intermediate register and LENGTH -// is the number of bytes to copy (which may be smaller than VT). -multiclass MVCLoadStore length> { - def Pat : PatFrag<(ops node:$dest, node:$src), - (store (vt (load node:$src)), node:$dest), - [{ return storeLoadCanUseMVC(N); }]>; - - def : Pat<(!cast(NAME##"Pat") bdaddr12only:$dest, - bdaddr12only:$src), +// Try to use MVC instruction INSN for a load of type LOAD followed by a store +// of the same size. VT is the type of the intermediate (legalized) value and +// LENGTH is the number of bytes loaded by LOAD. +multiclass MVCLoadStore length> { + def : Pat<(mvc_store (vt (load bdaddr12only:$src)), bdaddr12only:$dest), (insn bdaddr12only:$dest, bdaddr12only:$src, length)>; } +// Use NC-like instruction INSN for block_op operation OPERATOR. +// The other operand is a load of type LOAD, which accesses LENGTH bytes. +// VT is the intermediate legalized type in which the binary operation +// is actually done. +multiclass BinaryLoadStore length> { + def : Pat<(operator (vt (load bdaddr12only:$src)), bdaddr12only:$dest), + (insn bdaddr12only:$dest, bdaddr12only:$src, length)>; +} + +// A convenient way of generating all block peepholes for a particular +// LOAD/VT/LENGTH combination. +multiclass BlockLoadStore length> { + defm : MVCLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; + defm : BinaryLoadStore; +} + // Record that INSN is a LOAD AND TEST that can be used to compare // registers in CLS against zero. The instruction has separate R1 and R2 // operands, but they must be the same when the instruction is used like this. diff --git a/test/CodeGen/SystemZ/and-08.ll b/test/CodeGen/SystemZ/and-08.ll new file mode 100644 index 00000000000..f2ab6699cfd --- /dev/null +++ b/test/CodeGen/SystemZ/and-08.ll @@ -0,0 +1,397 @@ +; Test memory-to-memory ANDs. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +@g1 = global i8 1 +@g2 = global i16 2 + +; Test the simple i8 case. +define void @f1(i8 *%ptr1) { +; CHECK-LABEL: f1: +; CHECK: nc 1(1,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i8 *%ptr1, i64 1 + %val = load i8 *%ptr1 + %old = load i8 *%ptr2 + %and = and i8 %val, %old + store i8 %and, i8 *%ptr2 + ret void +} + +; ...and again in reverse. +define void @f2(i8 *%ptr1) { +; CHECK-LABEL: f2: +; CHECK: nc 1(1,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i8 *%ptr1, i64 1 + %val = load i8 *%ptr1 + %old = load i8 *%ptr2 + %and = and i8 %old, %val + store i8 %and, i8 *%ptr2 + ret void +} + +; Test i8 cases where one value is zero-extended to 32 bits and the other +; sign-extended. +define void @f3(i8 *%ptr1) { +; CHECK-LABEL: f3: +; CHECK: nc 1(1,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i8 *%ptr1, i64 1 + %val = load i8 *%ptr1 + %extval = zext i8 %val to i32 + %old = load i8 *%ptr2 + %extold = sext i8 %old to i32 + %and = and i32 %extval, %extold + %trunc = trunc i32 %and to i8 + store i8 %trunc, i8 *%ptr2 + ret void +} + +; ...and again with the extension types reversed. +define void @f4(i8 *%ptr1) { +; CHECK-LABEL: f4: +; CHECK: nc 1(1,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i8 *%ptr1, i64 1 + %val = load i8 *%ptr1 + %extval = sext i8 %val to i32 + %old = load i8 *%ptr2 + %extold = zext i8 %old to i32 + %and = and i32 %extval, %extold + %trunc = trunc i32 %and to i8 + store i8 %trunc, i8 *%ptr2 + ret void +} + +; ...and again with two sign extensions. +define void @f5(i8 *%ptr1) { +; CHECK-LABEL: f5: +; CHECK: nc 1(1,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i8 *%ptr1, i64 1 + %val = load i8 *%ptr1 + %extval = sext i8 %val to i32 + %old = load i8 *%ptr2 + %extold = sext i8 %old to i32 + %and = and i32 %extval, %extold + %trunc = trunc i32 %and to i8 + store i8 %trunc, i8 *%ptr2 + ret void +} + +; ...and again with two zero extensions. +define void @f6(i8 *%ptr1) { +; CHECK-LABEL: f6: +; CHECK: nc 1(1,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i8 *%ptr1, i64 1 + %val = load i8 *%ptr1 + %extval = zext i8 %val to i32 + %old = load i8 *%ptr2 + %extold = zext i8 %old to i32 + %and = and i32 %extval, %extold + %trunc = trunc i32 %and to i8 + store i8 %trunc, i8 *%ptr2 + ret void +} + +; Test i8 cases where the value is extended to 64 bits (just one case +; this time). +define void @f7(i8 *%ptr1) { +; CHECK-LABEL: f7: +; CHECK: nc 1(1,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i8 *%ptr1, i64 1 + %val = load i8 *%ptr1 + %extval = sext i8 %val to i64 + %old = load i8 *%ptr2 + %extold = zext i8 %old to i64 + %and = and i64 %extval, %extold + %trunc = trunc i64 %and to i8 + store i8 %trunc, i8 *%ptr2 + ret void +} + +; Test the simple i16 case. +define void @f8(i16 *%ptr1) { +; CHECK-LABEL: f8: +; CHECK: nc 2(2,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i16 *%ptr1, i64 1 + %val = load i16 *%ptr1 + %old = load i16 *%ptr2 + %and = and i16 %val, %old + store i16 %and, i16 *%ptr2 + ret void +} + +; Test i16 cases where the value is extended to 32 bits. +define void @f9(i16 *%ptr1) { +; CHECK-LABEL: f9: +; CHECK: nc 2(2,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i16 *%ptr1, i64 1 + %val = load i16 *%ptr1 + %extval = zext i16 %val to i32 + %old = load i16 *%ptr2 + %extold = sext i16 %old to i32 + %and = and i32 %extval, %extold + %trunc = trunc i32 %and to i16 + store i16 %trunc, i16 *%ptr2 + ret void +} + +; Test i16 cases where the value is extended to 64 bits. +define void @f10(i16 *%ptr1) { +; CHECK-LABEL: f10: +; CHECK: nc 2(2,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i16 *%ptr1, i64 1 + %val = load i16 *%ptr1 + %extval = sext i16 %val to i64 + %old = load i16 *%ptr2 + %extold = zext i16 %old to i64 + %and = and i64 %extval, %extold + %trunc = trunc i64 %and to i16 + store i16 %trunc, i16 *%ptr2 + ret void +} + +; Test the simple i32 case. +define void @f11(i32 *%ptr1) { +; CHECK-LABEL: f11: +; CHECK: nc 4(4,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i32 *%ptr1, i64 1 + %val = load i32 *%ptr1 + %old = load i32 *%ptr2 + %and = and i32 %old, %val + store i32 %and, i32 *%ptr2 + ret void +} + +; Test i32 cases where the value is extended to 64 bits. +define void @f12(i32 *%ptr1) { +; CHECK-LABEL: f12: +; CHECK: nc 4(4,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i32 *%ptr1, i64 1 + %val = load i32 *%ptr1 + %extval = sext i32 %val to i64 + %old = load i32 *%ptr2 + %extold = zext i32 %old to i64 + %and = and i64 %extval, %extold + %trunc = trunc i64 %and to i32 + store i32 %trunc, i32 *%ptr2 + ret void +} + +; Test the i64 case. +define void @f13(i64 *%ptr1) { +; CHECK-LABEL: f13: +; CHECK: nc 8(8,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i64 *%ptr1, i64 1 + %val = load i64 *%ptr1 + %old = load i64 *%ptr2 + %and = and i64 %old, %val + store i64 %and, i64 *%ptr2 + ret void +} + +; Make sure that we don't use NC if the first load is volatile. +define void @f14(i64 *%ptr1) { +; CHECK-LABEL: f14: +; CHECK-NOT: nc +; CHECK: br %r14 + %ptr2 = getelementptr i64 *%ptr1, i64 1 + %val = load volatile i64 *%ptr1 + %old = load i64 *%ptr2 + %and = and i64 %old, %val + store i64 %and, i64 *%ptr2 + ret void +} + +; ...likewise the second. +define void @f15(i64 *%ptr1) { +; CHECK-LABEL: f15: +; CHECK-NOT: nc +; CHECK: br %r14 + %ptr2 = getelementptr i64 *%ptr1, i64 1 + %val = load i64 *%ptr1 + %old = load volatile i64 *%ptr2 + %and = and i64 %old, %val + store i64 %and, i64 *%ptr2 + ret void +} + +; ...likewise the store. +define void @f16(i64 *%ptr1) { +; CHECK-LABEL: f16: +; CHECK-NOT: nc +; CHECK: br %r14 + %ptr2 = getelementptr i64 *%ptr1, i64 1 + %val = load i64 *%ptr1 + %old = load i64 *%ptr2 + %and = and i64 %old, %val + store volatile i64 %and, i64 *%ptr2 + ret void +} + +; Test that NC is used for aligned loads and stores, even if there is +; no way of telling whether they alias. +define void @f17(i64 *%ptr1, i64 *%ptr2) { +; CHECK-LABEL: f17: +; CHECK: nc 0(8,%r3), 0(%r2) +; CHECK: br %r14 + %val = load i64 *%ptr1 + %old = load i64 *%ptr2 + %and = and i64 %old, %val + store i64 %and, i64 *%ptr2 + ret void +} + +; ...but if one of the loads isn't aligned, we can't be sure. +define void @f18(i64 *%ptr1, i64 *%ptr2) { +; CHECK-LABEL: f18: +; CHECK-NOT: nc +; CHECK: br %r14 + %val = load i64 *%ptr1, align 2 + %old = load i64 *%ptr2 + %and = and i64 %old, %val + store i64 %and, i64 *%ptr2 + ret void +} + +; Repeat the previous test with the operands in the opposite order. +define void @f19(i64 *%ptr1, i64 *%ptr2) { +; CHECK-LABEL: f19: +; CHECK-NOT: nc +; CHECK: br %r14 + %val = load i64 *%ptr1, align 2 + %old = load i64 *%ptr2 + %and = and i64 %val, %old + store i64 %and, i64 *%ptr2 + ret void +} + +; ...and again with the other operand being unaligned. +define void @f20(i64 *%ptr1, i64 *%ptr2) { +; CHECK-LABEL: f20: +; CHECK-NOT: nc +; CHECK: br %r14 + %val = load i64 *%ptr1 + %old = load i64 *%ptr2, align 2 + %and = and i64 %val, %old + store i64 %and, i64 *%ptr2, align 2 + ret void +} + +; Test a case where there is definite overlap. +define void @f21(i64 %base) { +; CHECK-LABEL: f21: +; CHECK-NOT: nc +; CHECK: br %r14 + %add = add i64 %base, 1 + %ptr1 = inttoptr i64 %base to i64 * + %ptr2 = inttoptr i64 %add to i64 * + %val = load i64 *%ptr1 + %old = load i64 *%ptr2, align 1 + %and = and i64 %old, %val + store i64 %and, i64 *%ptr2, align 1 + ret void +} + +; Test that we can use NC for global addresses for i8. +define void @f22(i8 *%ptr) { +; CHECK-LABEL: f22: +; CHECK: larl [[REG:%r[0-5]]], g1 +; CHECK: nc 0(1,%r2), 0([[REG]]) +; CHECK: br %r14 + %val = load i8 *@g1 + %old = load i8 *%ptr + %and = and i8 %val, %old + store i8 %and, i8 *%ptr + ret void +} + +; ...and again with the global on the store. +define void @f23(i8 *%ptr) { +; CHECK-LABEL: f23: +; CHECK: larl [[REG:%r[0-5]]], g1 +; CHECK: nc 0(1,[[REG]]), 0(%r2) +; CHECK: br %r14 + %val = load i8 *%ptr + %old = load i8 *@g1 + %and = and i8 %val, %old + store i8 %and, i8 *@g1 + ret void +} + +; Test that we use NC even where LHRL and STHRL are available. +define void @f24(i16 *%ptr) { +; CHECK-LABEL: f24: +; CHECK: larl [[REG:%r[0-5]]], g2 +; CHECK: nc 0(2,%r2), 0([[REG]]) +; CHECK: br %r14 + %val = load i16 *@g2 + %old = load i16 *%ptr + %and = and i16 %val, %old + store i16 %and, i16 *%ptr + ret void +} + +; ...likewise on the other side. +define void @f25(i16 *%ptr) { +; CHECK-LABEL: f25: +; CHECK: larl [[REG:%r[0-5]]], g2 +; CHECK: nc 0(2,[[REG]]), 0(%r2) +; CHECK: br %r14 + %val = load i16 *%ptr + %old = load i16 *@g2 + %and = and i16 %val, %old + store i16 %and, i16 *@g2 + ret void +} + +; Test a case where offset disambiguation is enough. +define void @f26(i64 *%ptr1) { +; CHECK-LABEL: f26: +; CHECK: nc 8(8,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i64 *%ptr1, i64 1 + %val = load i64 *%ptr1, align 1 + %old = load i64 *%ptr2, align 1 + %and = and i64 %old, %val + store i64 %and, i64 *%ptr2, align 1 + ret void +} + +; Test a case where TBAA tells us there is no alias. +define void @f27(i64 *%ptr1, i64 *%ptr2) { +; CHECK-LABEL: f27: +; CHECK: nc 0(8,%r3), 0(%r2) +; CHECK: br %r14 + %val = load i64 *%ptr1, align 2, !tbaa !1 + %old = load i64 *%ptr2, align 2, !tbaa !2 + %and = and i64 %old, %val + store i64 %and, i64 *%ptr2, align 2, !tbaa !2 + ret void +} + +; Test a case where TBAA information is present but doesn't help. +define void @f28(i64 *%ptr1, i64 *%ptr2) { +; CHECK-LABEL: f28: +; CHECK-NOT: nc +; CHECK: br %r14 + %val = load i64 *%ptr1, align 2, !tbaa !1 + %old = load i64 *%ptr2, align 2, !tbaa !1 + %and = and i64 %old, %val + store i64 %and, i64 *%ptr2, align 2, !tbaa !1 + ret void +} + +!0 = metadata !{ metadata !"root" } +!1 = metadata !{ metadata !"set1", metadata !0 } +!2 = metadata !{ metadata !"set2", metadata !0 } diff --git a/test/CodeGen/SystemZ/or-08.ll b/test/CodeGen/SystemZ/or-08.ll new file mode 100644 index 00000000000..8f5bf3170be --- /dev/null +++ b/test/CodeGen/SystemZ/or-08.ll @@ -0,0 +1,57 @@ +; Test memory-to-memory ORs. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; Test the simple i8 case. +define void @f1(i8 *%ptr1) { +; CHECK-LABEL: f1: +; CHECK: oc 1(1,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i8 *%ptr1, i64 1 + %val = load i8 *%ptr1 + %old = load i8 *%ptr2 + %or = or i8 %val, %old + store i8 %or, i8 *%ptr2 + ret void +} + +; Test the simple i16 case. +define void @f2(i16 *%ptr1) { +; CHECK-LABEL: f2: +; CHECK: oc 2(2,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i16 *%ptr1, i64 1 + %val = load i16 *%ptr1 + %old = load i16 *%ptr2 + %or = or i16 %val, %old + store i16 %or, i16 *%ptr2 + ret void +} + +; Test the simple i32 case. +define void @f3(i32 *%ptr1) { +; CHECK-LABEL: f3: +; CHECK: oc 4(4,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i32 *%ptr1, i64 1 + %val = load i32 *%ptr1 + %old = load i32 *%ptr2 + %or = or i32 %old, %val + store i32 %or, i32 *%ptr2 + ret void +} + +; Test the i64 case. +define void @f4(i64 *%ptr1) { +; CHECK-LABEL: f4: +; CHECK: oc 8(8,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i64 *%ptr1, i64 1 + %val = load i64 *%ptr1 + %old = load i64 *%ptr2 + %or = or i64 %old, %val + store i64 %or, i64 *%ptr2 + ret void +} + +; Leave other more complicated tests to and-08.ll. diff --git a/test/CodeGen/SystemZ/xor-08.ll b/test/CodeGen/SystemZ/xor-08.ll new file mode 100644 index 00000000000..8cba41e742c --- /dev/null +++ b/test/CodeGen/SystemZ/xor-08.ll @@ -0,0 +1,57 @@ +; Test memory-to-memory XORs. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +; Test the simple i8 case. +define void @f1(i8 *%ptr1) { +; CHECK-LABEL: f1: +; CHECK: xc 1(1,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i8 *%ptr1, i64 1 + %val = load i8 *%ptr1 + %old = load i8 *%ptr2 + %xor = xor i8 %val, %old + store i8 %xor, i8 *%ptr2 + ret void +} + +; Test the simple i16 case. +define void @f2(i16 *%ptr1) { +; CHECK-LABEL: f2: +; CHECK: xc 2(2,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i16 *%ptr1, i64 1 + %val = load i16 *%ptr1 + %old = load i16 *%ptr2 + %xor = xor i16 %val, %old + store i16 %xor, i16 *%ptr2 + ret void +} + +; Test the simple i32 case. +define void @f3(i32 *%ptr1) { +; CHECK-LABEL: f3: +; CHECK: xc 4(4,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i32 *%ptr1, i64 1 + %val = load i32 *%ptr1 + %old = load i32 *%ptr2 + %xor = xor i32 %old, %val + store i32 %xor, i32 *%ptr2 + ret void +} + +; Test the i64 case. +define void @f4(i64 *%ptr1) { +; CHECK-LABEL: f4: +; CHECK: xc 8(8,%r2), 0(%r2) +; CHECK: br %r14 + %ptr2 = getelementptr i64 *%ptr1, i64 1 + %val = load i64 *%ptr1 + %old = load i64 *%ptr2 + %xor = xor i64 %old, %val + store i64 %xor, i64 *%ptr2 + ret void +} + +; Leave other more complicated tests to and-08.ll. diff --git a/test/MC/Disassembler/SystemZ/insns.txt b/test/MC/Disassembler/SystemZ/insns.txt index 912837c9a60..f2cf3224045 100644 --- a/test/MC/Disassembler/SystemZ/insns.txt +++ b/test/MC/Disassembler/SystemZ/insns.txt @@ -4861,6 +4861,42 @@ # CHECK: mxdb %f13, 0 0xed 0xd0 0x00 0x00 0x00 0x07 +# CHECK: nc 0(1), 0 +0xd4 0x00 0x00 0x00 0x00 0x00 + +# CHECK: nc 0(1), 0(%r1) +0xd4 0x00 0x00 0x00 0x10 0x00 + +# CHECK: nc 0(1), 0(%r15) +0xd4 0x00 0x00 0x00 0xf0 0x00 + +# CHECK: nc 0(1), 4095 +0xd4 0x00 0x00 0x00 0x0f 0xff + +# CHECK: nc 0(1), 4095(%r1) +0xd4 0x00 0x00 0x00 0x1f 0xff + +# CHECK: nc 0(1), 4095(%r15) +0xd4 0x00 0x00 0x00 0xff 0xff + +# CHECK: nc 0(1,%r1), 0 +0xd4 0x00 0x10 0x00 0x00 0x00 + +# CHECK: nc 0(1,%r15), 0 +0xd4 0x00 0xf0 0x00 0x00 0x00 + +# CHECK: nc 4095(1,%r1), 0 +0xd4 0x00 0x1f 0xff 0x00 0x00 + +# CHECK: nc 4095(1,%r15), 0 +0xd4 0x00 0xff 0xff 0x00 0x00 + +# CHECK: nc 0(256,%r1), 0 +0xd4 0xff 0x10 0x00 0x00 0x00 + +# CHECK: nc 0(256,%r15), 0 +0xd4 0xff 0xf0 0x00 0x00 0x00 + # CHECK: ngr %r0, %r0 0xb9 0x80 0x00 0x00 @@ -5095,6 +5131,42 @@ # CHECK: ny %r15, 0 0xe3 0xf0 0x00 0x00 0x00 0x54 +# CHECK: oc 0(1), 0 +0xd6 0x00 0x00 0x00 0x00 0x00 + +# CHECK: oc 0(1), 0(%r1) +0xd6 0x00 0x00 0x00 0x10 0x00 + +# CHECK: oc 0(1), 0(%r15) +0xd6 0x00 0x00 0x00 0xf0 0x00 + +# CHECK: oc 0(1), 4095 +0xd6 0x00 0x00 0x00 0x0f 0xff + +# CHECK: oc 0(1), 4095(%r1) +0xd6 0x00 0x00 0x00 0x1f 0xff + +# CHECK: oc 0(1), 4095(%r15) +0xd6 0x00 0x00 0x00 0xff 0xff + +# CHECK: oc 0(1,%r1), 0 +0xd6 0x00 0x10 0x00 0x00 0x00 + +# CHECK: oc 0(1,%r15), 0 +0xd6 0x00 0xf0 0x00 0x00 0x00 + +# CHECK: oc 4095(1,%r1), 0 +0xd6 0x00 0x1f 0xff 0x00 0x00 + +# CHECK: oc 4095(1,%r15), 0 +0xd6 0x00 0xff 0xff 0x00 0x00 + +# CHECK: oc 0(256,%r1), 0 +0xd6 0xff 0x10 0x00 0x00 0x00 + +# CHECK: oc 0(256,%r15), 0 +0xd6 0xff 0xf0 0x00 0x00 0x00 + # CHECK: ogr %r0, %r0 0xb9 0x81 0x00 0x00 @@ -7012,6 +7084,42 @@ # CHECK: tmll %r15, 0 0xa7 0xf1 0x00 0x00 +# CHECK: xc 0(1), 0 +0xd7 0x00 0x00 0x00 0x00 0x00 + +# CHECK: xc 0(1), 0(%r1) +0xd7 0x00 0x00 0x00 0x10 0x00 + +# CHECK: xc 0(1), 0(%r15) +0xd7 0x00 0x00 0x00 0xf0 0x00 + +# CHECK: xc 0(1), 4095 +0xd7 0x00 0x00 0x00 0x0f 0xff + +# CHECK: xc 0(1), 4095(%r1) +0xd7 0x00 0x00 0x00 0x1f 0xff + +# CHECK: xc 0(1), 4095(%r15) +0xd7 0x00 0x00 0x00 0xff 0xff + +# CHECK: xc 0(1,%r1), 0 +0xd7 0x00 0x10 0x00 0x00 0x00 + +# CHECK: xc 0(1,%r15), 0 +0xd7 0x00 0xf0 0x00 0x00 0x00 + +# CHECK: xc 4095(1,%r1), 0 +0xd7 0x00 0x1f 0xff 0x00 0x00 + +# CHECK: xc 4095(1,%r15), 0 +0xd7 0x00 0xff 0xff 0x00 0x00 + +# CHECK: xc 0(256,%r1), 0 +0xd7 0xff 0x10 0x00 0x00 0x00 + +# CHECK: xc 0(256,%r15), 0 +0xd7 0xff 0xf0 0x00 0x00 0x00 + # CHECK: xgr %r0, %r0 0xb9 0x82 0x00 0x00 diff --git a/test/MC/SystemZ/insn-bad.s b/test/MC/SystemZ/insn-bad.s index 54979fdaf91..a7affaef2fa 100644 --- a/test/MC/SystemZ/insn-bad.s +++ b/test/MC/SystemZ/insn-bad.s @@ -2051,6 +2051,50 @@ n %r0, -1 n %r0, 4096 +#CHECK: error: missing length in address +#CHECK: nc 0, 0 +#CHECK: error: missing length in address +#CHECK: nc 0(%r1), 0(%r1) +#CHECK: error: invalid use of length addressing +#CHECK: nc 0(1,%r1), 0(2,%r1) +#CHECK: error: invalid operand +#CHECK: nc 0(0,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: nc 0(257,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: nc -1(1,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: nc 4096(1,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: nc 0(1,%r1), -1(%r1) +#CHECK: error: invalid operand +#CHECK: nc 0(1,%r1), 4096(%r1) +#CHECK: error: %r0 used in an address +#CHECK: nc 0(1,%r0), 0(%r1) +#CHECK: error: %r0 used in an address +#CHECK: nc 0(1,%r1), 0(%r0) +#CHECK: error: invalid use of indexed addressing +#CHECK: nc 0(%r1,%r2), 0(%r1) +#CHECK: error: invalid use of indexed addressing +#CHECK: nc 0(1,%r2), 0(%r1,%r2) +#CHECK: error: unknown token in expression +#CHECK: nc 0(-), 0 + + nc 0, 0 + nc 0(%r1), 0(%r1) + nc 0(1,%r1), 0(2,%r1) + nc 0(0,%r1), 0(%r1) + nc 0(257,%r1), 0(%r1) + nc -1(1,%r1), 0(%r1) + nc 4096(1,%r1), 0(%r1) + nc 0(1,%r1), -1(%r1) + nc 0(1,%r1), 4096(%r1) + nc 0(1,%r0), 0(%r1) + nc 0(1,%r1), 0(%r0) + nc 0(%r1,%r2), 0(%r1) + nc 0(1,%r2), 0(%r1,%r2) + nc 0(-), 0 + #CHECK: error: invalid operand #CHECK: ng %r0, -524289 #CHECK: error: invalid operand @@ -2167,6 +2211,50 @@ o %r0, -1 o %r0, 4096 +#CHECK: error: missing length in address +#CHECK: oc 0, 0 +#CHECK: error: missing length in address +#CHECK: oc 0(%r1), 0(%r1) +#CHECK: error: invalid use of length addressing +#CHECK: oc 0(1,%r1), 0(2,%r1) +#CHECK: error: invalid operand +#CHECK: oc 0(0,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: oc 0(257,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: oc -1(1,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: oc 4096(1,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: oc 0(1,%r1), -1(%r1) +#CHECK: error: invalid operand +#CHECK: oc 0(1,%r1), 4096(%r1) +#CHECK: error: %r0 used in an address +#CHECK: oc 0(1,%r0), 0(%r1) +#CHECK: error: %r0 used in an address +#CHECK: oc 0(1,%r1), 0(%r0) +#CHECK: error: invalid use of indexed addressing +#CHECK: oc 0(%r1,%r2), 0(%r1) +#CHECK: error: invalid use of indexed addressing +#CHECK: oc 0(1,%r2), 0(%r1,%r2) +#CHECK: error: unknown token in expression +#CHECK: oc 0(-), 0 + + oc 0, 0 + oc 0(%r1), 0(%r1) + oc 0(1,%r1), 0(2,%r1) + oc 0(0,%r1), 0(%r1) + oc 0(257,%r1), 0(%r1) + oc -1(1,%r1), 0(%r1) + oc 4096(1,%r1), 0(%r1) + oc 0(1,%r1), -1(%r1) + oc 0(1,%r1), 4096(%r1) + oc 0(1,%r0), 0(%r1) + oc 0(1,%r1), 0(%r0) + oc 0(%r1,%r2), 0(%r1) + oc 0(1,%r2), 0(%r1,%r2) + oc 0(-), 0 + #CHECK: error: invalid operand #CHECK: og %r0, -524289 #CHECK: error: invalid operand @@ -2903,6 +2991,50 @@ x %r0, -1 x %r0, 4096 +#CHECK: error: missing length in address +#CHECK: xc 0, 0 +#CHECK: error: missing length in address +#CHECK: xc 0(%r1), 0(%r1) +#CHECK: error: invalid use of length addressing +#CHECK: xc 0(1,%r1), 0(2,%r1) +#CHECK: error: invalid operand +#CHECK: xc 0(0,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: xc 0(257,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: xc -1(1,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: xc 4096(1,%r1), 0(%r1) +#CHECK: error: invalid operand +#CHECK: xc 0(1,%r1), -1(%r1) +#CHECK: error: invalid operand +#CHECK: xc 0(1,%r1), 4096(%r1) +#CHECK: error: %r0 used in an address +#CHECK: xc 0(1,%r0), 0(%r1) +#CHECK: error: %r0 used in an address +#CHECK: xc 0(1,%r1), 0(%r0) +#CHECK: error: invalid use of indexed addressing +#CHECK: xc 0(%r1,%r2), 0(%r1) +#CHECK: error: invalid use of indexed addressing +#CHECK: xc 0(1,%r2), 0(%r1,%r2) +#CHECK: error: unknown token in expression +#CHECK: xc 0(-), 0 + + xc 0, 0 + xc 0(%r1), 0(%r1) + xc 0(1,%r1), 0(2,%r1) + xc 0(0,%r1), 0(%r1) + xc 0(257,%r1), 0(%r1) + xc -1(1,%r1), 0(%r1) + xc 4096(1,%r1), 0(%r1) + xc 0(1,%r1), -1(%r1) + xc 0(1,%r1), 4096(%r1) + xc 0(1,%r0), 0(%r1) + xc 0(1,%r1), 0(%r0) + xc 0(%r1,%r2), 0(%r1) + xc 0(1,%r2), 0(%r1,%r2) + xc 0(-), 0 + #CHECK: error: invalid operand #CHECK: xg %r0, -524289 #CHECK: error: invalid operand diff --git a/test/MC/SystemZ/insn-good.s b/test/MC/SystemZ/insn-good.s index be7e3085496..0cbccc4a299 100644 --- a/test/MC/SystemZ/insn-good.s +++ b/test/MC/SystemZ/insn-good.s @@ -5774,6 +5774,32 @@ n %r0, 4095(%r15,%r1) n %r15, 0 +#CHECK: nc 0(1), 0 # encoding: [0xd4,0x00,0x00,0x00,0x00,0x00] +#CHECK: nc 0(1), 0(%r1) # encoding: [0xd4,0x00,0x00,0x00,0x10,0x00] +#CHECK: nc 0(1), 0(%r15) # encoding: [0xd4,0x00,0x00,0x00,0xf0,0x00] +#CHECK: nc 0(1), 4095 # encoding: [0xd4,0x00,0x00,0x00,0x0f,0xff] +#CHECK: nc 0(1), 4095(%r1) # encoding: [0xd4,0x00,0x00,0x00,0x1f,0xff] +#CHECK: nc 0(1), 4095(%r15) # encoding: [0xd4,0x00,0x00,0x00,0xff,0xff] +#CHECK: nc 0(1,%r1), 0 # encoding: [0xd4,0x00,0x10,0x00,0x00,0x00] +#CHECK: nc 0(1,%r15), 0 # encoding: [0xd4,0x00,0xf0,0x00,0x00,0x00] +#CHECK: nc 4095(1,%r1), 0 # encoding: [0xd4,0x00,0x1f,0xff,0x00,0x00] +#CHECK: nc 4095(1,%r15), 0 # encoding: [0xd4,0x00,0xff,0xff,0x00,0x00] +#CHECK: nc 0(256,%r1), 0 # encoding: [0xd4,0xff,0x10,0x00,0x00,0x00] +#CHECK: nc 0(256,%r15), 0 # encoding: [0xd4,0xff,0xf0,0x00,0x00,0x00] + + nc 0(1), 0 + nc 0(1), 0(%r1) + nc 0(1), 0(%r15) + nc 0(1), 4095 + nc 0(1), 4095(%r1) + nc 0(1), 4095(%r15) + nc 0(1,%r1), 0 + nc 0(1,%r15), 0 + nc 4095(1,%r1), 0 + nc 4095(1,%r15), 0 + nc 0(256,%r1), 0 + nc 0(256,%r15), 0 + #CHECK: ng %r0, -524288 # encoding: [0xe3,0x00,0x00,0x00,0x80,0x80] #CHECK: ng %r0, -1 # encoding: [0xe3,0x00,0x0f,0xff,0xff,0x80] #CHECK: ng %r0, 0 # encoding: [0xe3,0x00,0x00,0x00,0x00,0x80] @@ -5948,6 +5974,32 @@ o %r0, 4095(%r15,%r1) o %r15, 0 +#CHECK: oc 0(1), 0 # encoding: [0xd6,0x00,0x00,0x00,0x00,0x00] +#CHECK: oc 0(1), 0(%r1) # encoding: [0xd6,0x00,0x00,0x00,0x10,0x00] +#CHECK: oc 0(1), 0(%r15) # encoding: [0xd6,0x00,0x00,0x00,0xf0,0x00] +#CHECK: oc 0(1), 4095 # encoding: [0xd6,0x00,0x00,0x00,0x0f,0xff] +#CHECK: oc 0(1), 4095(%r1) # encoding: [0xd6,0x00,0x00,0x00,0x1f,0xff] +#CHECK: oc 0(1), 4095(%r15) # encoding: [0xd6,0x00,0x00,0x00,0xff,0xff] +#CHECK: oc 0(1,%r1), 0 # encoding: [0xd6,0x00,0x10,0x00,0x00,0x00] +#CHECK: oc 0(1,%r15), 0 # encoding: [0xd6,0x00,0xf0,0x00,0x00,0x00] +#CHECK: oc 4095(1,%r1), 0 # encoding: [0xd6,0x00,0x1f,0xff,0x00,0x00] +#CHECK: oc 4095(1,%r15), 0 # encoding: [0xd6,0x00,0xff,0xff,0x00,0x00] +#CHECK: oc 0(256,%r1), 0 # encoding: [0xd6,0xff,0x10,0x00,0x00,0x00] +#CHECK: oc 0(256,%r15), 0 # encoding: [0xd6,0xff,0xf0,0x00,0x00,0x00] + + oc 0(1), 0 + oc 0(1), 0(%r1) + oc 0(1), 0(%r15) + oc 0(1), 4095 + oc 0(1), 4095(%r1) + oc 0(1), 4095(%r15) + oc 0(1,%r1), 0 + oc 0(1,%r15), 0 + oc 4095(1,%r1), 0 + oc 4095(1,%r15), 0 + oc 0(256,%r1), 0 + oc 0(256,%r15), 0 + #CHECK: og %r0, -524288 # encoding: [0xe3,0x00,0x00,0x00,0x80,0x81] #CHECK: og %r0, -1 # encoding: [0xe3,0x00,0x0f,0xff,0xff,0x81] #CHECK: og %r0, 0 # encoding: [0xe3,0x00,0x00,0x00,0x00,0x81] @@ -7340,6 +7392,32 @@ x %r0, 4095(%r15,%r1) x %r15, 0 +#CHECK: xc 0(1), 0 # encoding: [0xd7,0x00,0x00,0x00,0x00,0x00] +#CHECK: xc 0(1), 0(%r1) # encoding: [0xd7,0x00,0x00,0x00,0x10,0x00] +#CHECK: xc 0(1), 0(%r15) # encoding: [0xd7,0x00,0x00,0x00,0xf0,0x00] +#CHECK: xc 0(1), 4095 # encoding: [0xd7,0x00,0x00,0x00,0x0f,0xff] +#CHECK: xc 0(1), 4095(%r1) # encoding: [0xd7,0x00,0x00,0x00,0x1f,0xff] +#CHECK: xc 0(1), 4095(%r15) # encoding: [0xd7,0x00,0x00,0x00,0xff,0xff] +#CHECK: xc 0(1,%r1), 0 # encoding: [0xd7,0x00,0x10,0x00,0x00,0x00] +#CHECK: xc 0(1,%r15), 0 # encoding: [0xd7,0x00,0xf0,0x00,0x00,0x00] +#CHECK: xc 4095(1,%r1), 0 # encoding: [0xd7,0x00,0x1f,0xff,0x00,0x00] +#CHECK: xc 4095(1,%r15), 0 # encoding: [0xd7,0x00,0xff,0xff,0x00,0x00] +#CHECK: xc 0(256,%r1), 0 # encoding: [0xd7,0xff,0x10,0x00,0x00,0x00] +#CHECK: xc 0(256,%r15), 0 # encoding: [0xd7,0xff,0xf0,0x00,0x00,0x00] + + xc 0(1), 0 + xc 0(1), 0(%r1) + xc 0(1), 0(%r15) + xc 0(1), 4095 + xc 0(1), 4095(%r1) + xc 0(1), 4095(%r15) + xc 0(1,%r1), 0 + xc 0(1,%r15), 0 + xc 4095(1,%r1), 0 + xc 4095(1,%r15), 0 + xc 0(256,%r1), 0 + xc 0(256,%r15), 0 + #CHECK: xg %r0, -524288 # encoding: [0xe3,0x00,0x00,0x00,0x80,0x82] #CHECK: xg %r0, -1 # encoding: [0xe3,0x00,0x0f,0xff,0xff,0x82] #CHECK: xg %r0, 0 # encoding: [0xe3,0x00,0x00,0x00,0x00,0x82]