[llvm] 86bd12d - [SystemZ] Fold i16/i32/i64 logical RMW operations into memory operands in TableGen (#192802)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 5 03:48:04 PDT 2026
Author: anoopkg6
Date: 2026-08-05T12:47:59+02:00
New Revision: 86bd12d5cb40103937484a43386801b4e5353da5
URL: https://github.com/llvm/llvm-project/commit/86bd12d5cb40103937484a43386801b4e5353da5
DIFF: https://github.com/llvm/llvm-project/commit/86bd12d5cb40103937484a43386801b4e5353da5.diff
LOG: [SystemZ] Fold i16/i32/i64 logical RMW operations into memory operands in TableGen (#192802)
Add support for folding logical operations with 8-bit immediates into
memory operands for i16, i32, and i64 types to target LSB. It handles
both 12-bit (NI, OI, XI) and 20-bit signed (NIY, OIY, XIY) displacements.
---------
Co-authored-by: anoopkg6 <anoopkg6 at github.com>
Added:
Modified:
llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
llvm/lib/Target/SystemZ/SystemZInstrInfo.td
llvm/lib/Target/SystemZ/SystemZOperands.td
llvm/lib/Target/SystemZ/SystemZOperators.td
llvm/lib/Target/SystemZ/SystemZPatterns.td
llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp
llvm/test/Analysis/CostModel/SystemZ/fold-rmw-cost.ll
llvm/test/CodeGen/SystemZ/and-05.ll
llvm/test/CodeGen/SystemZ/or-05.ll
llvm/test/CodeGen/SystemZ/xor-05.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
index bb148c2dc2ebd..cb09611db7d16 100644
--- a/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp
@@ -165,7 +165,7 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
// Return true on success, storing the base and displacement in
// Base and Disp respectively.
bool selectBDAddr(SystemZAddressingMode::DispRange DR, SDValue Addr,
- SDValue &Base, SDValue &Disp) const;
+ SDValue &Base, SDValue &Disp, int64_t Offset = 0) const;
// Try to match Addr as a FormBDX address with displacement type DR.
// Return true on success and if the result had no index. Store the
@@ -267,6 +267,15 @@ class SystemZDAGToDAGISel : public SelectionDAGISel {
// in Base, Disp and Index respectively.
bool selectBDVAddr12Only(SDValue Addr, SDValue Elem, SDValue &Base,
SDValue &Disp, SDValue &Index) const;
+ // Wrapper functions for LSB access on big-endian multi-byte types.
+ // Selects a Base + Displacement address and applies a fixed byte Offset.
+ // Offsets: i16 LSB = +1, i32 LSB = +3, i64 LSB = +7.
+ bool selectBDAddr12off1(SDValue Addr, SDValue &Base, SDValue &Disp) const;
+ bool selectBDAddr12off3(SDValue Addr, SDValue &Base, SDValue &Disp) const;
+ bool selectBDAddr12off7(SDValue Addr, SDValue &Base, SDValue &Disp) const;
+ bool selectBDAddr20off1(SDValue Addr, SDValue &Base, SDValue &Disp) const;
+ bool selectBDAddr20off3(SDValue Addr, SDValue &Base, SDValue &Disp) const;
+ bool selectBDAddr20off7(SDValue Addr, SDValue &Base, SDValue &Disp) const;
// Check whether (or Op (and X InsertMask)) is effectively an insertion
// of X into bits InsertMask of some Y != Op. Return true if so and
@@ -693,8 +702,9 @@ void SystemZDAGToDAGISel::getAddressOperands(const SystemZAddressingMode &AM,
bool SystemZDAGToDAGISel::selectBDAddr(SystemZAddressingMode::DispRange DR,
SDValue Addr, SDValue &Base,
- SDValue &Disp) const {
+ SDValue &Disp, int64_t Offset) const {
SystemZAddressingMode AM(SystemZAddressingMode::FormBD, DR);
+ AM.Disp += Offset;
if (!selectAddress(Addr, AM))
return false;
@@ -749,6 +759,32 @@ bool SystemZDAGToDAGISel::selectBDVAddr12Only(SDValue Addr, SDValue Elem,
return false;
}
+bool SystemZDAGToDAGISel::selectBDAddr12off1(SDValue A, SDValue &B,
+ SDValue &D) const {
+ return selectBDAddr(SystemZAddressingMode::Disp12Pair, A, B, D, 1);
+}
+bool SystemZDAGToDAGISel::selectBDAddr12off3(SDValue A, SDValue &B,
+ SDValue &D) const {
+ return selectBDAddr(SystemZAddressingMode::Disp12Pair, A, B, D, 3);
+}
+bool SystemZDAGToDAGISel::selectBDAddr12off7(SDValue A, SDValue &B,
+ SDValue &D) const {
+ return selectBDAddr(SystemZAddressingMode::Disp12Pair, A, B, D, 7);
+}
+
+bool SystemZDAGToDAGISel::selectBDAddr20off1(SDValue A, SDValue &B,
+ SDValue &D) const {
+ return selectBDAddr(SystemZAddressingMode::Disp20Pair, A, B, D, 1);
+}
+bool SystemZDAGToDAGISel::selectBDAddr20off3(SDValue A, SDValue &B,
+ SDValue &D) const {
+ return selectBDAddr(SystemZAddressingMode::Disp20Pair, A, B, D, 3);
+}
+bool SystemZDAGToDAGISel::selectBDAddr20off7(SDValue A, SDValue &B,
+ SDValue &D) const {
+ return selectBDAddr(SystemZAddressingMode::Disp20Pair, A, B, D, 7);
+}
+
bool SystemZDAGToDAGISel::detectOrAndInsertion(SDValue &Op,
uint64_t InsertMask) const {
// We're only interested in cases where the insertion is into some operand
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 693b171bcabf1..f53716a663ed8 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -1329,8 +1329,8 @@ let Defs = [CC] in {
let mayLoad = 1, mayStore = 1 in
defm NC : MemorySS<"nc", 0xD4, z_nc>;
}
-defm : RMWIByte<and, bdaddr12pair, NI>;
-defm : RMWIByte<and, bdaddr20pair, NIY>;
+defm : RMWIByte<and, NI, NIY, imm16ll8c, imm32ll8c,
+ imm16ll8c_i64, imm32ll8c_i64, imm64ll8c>;
//===----------------------------------------------------------------------===//
// OR
@@ -1386,8 +1386,7 @@ let Defs = [CC] in {
let mayLoad = 1, mayStore = 1 in
defm OC : MemorySS<"oc", 0xD6, z_oc>;
}
-defm : RMWIByte<or, bdaddr12pair, OI>;
-defm : RMWIByte<or, bdaddr20pair, OIY>;
+defm : RMWIByte<or, OI, OIY>;
//===----------------------------------------------------------------------===//
// XOR
@@ -1426,8 +1425,7 @@ let Defs = [CC] in {
let mayLoad = 1, mayStore = 1 in
defm XC : MemorySS<"xc", 0xD7, z_xc>;
}
-defm : RMWIByte<xor, bdaddr12pair, XI>;
-defm : RMWIByte<xor, bdaddr20pair, XIY>;
+defm : RMWIByte<xor, XI, XIY>;
//===----------------------------------------------------------------------===//
// Combined logical operations
diff --git a/llvm/lib/Target/SystemZ/SystemZOperands.td b/llvm/lib/Target/SystemZ/SystemZOperands.td
index 119bf4f7ca615..8a2049c518473 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperands.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperands.td
@@ -368,6 +368,19 @@ defm imm32zx8 : Immediate<i32, [{
defm imm32zx8trunc : Immediate<i32, [{}], UIMM8, "U8Imm">;
+// Immediates for the 8-bit LSB chunk of an i32, with the other bits being one.
+defm imm32ll8c : Immediate<i32, [{
+ return Imm.isIntN(32) &&
+ (uint32_t(~Imm.getZExtValue()) & ~0xffULL) == 0;
+}], UIMM8, "U8Imm">;
+
+// Immediates for the 8-bit LSB chunk of an i16 (evaluated as i32),
+// with the other bits being one.
+defm imm16ll8c : Immediate<i32, [{
+ return Imm.isIntN(16) &&
+ (uint16_t(~Imm.getZExtValue()) & ~0xffULL) == 0;
+}], UIMM8, "U8Imm">;
+
defm imm32zx12 : Immediate<i32, [{
return Imm.isIntN(12);
}], UIMM12, "U12Imm">;
@@ -486,6 +499,26 @@ defm imm64zx8 : Immediate<i64, [{
return Imm.isIntN(8);;
}], UIMM8, "U8Imm">;
+// Immediates for the 8-bit LSB chunk of an i64, with the other bits being one.
+defm imm64ll8c : Immediate<i64, [{
+ return Imm.isIntN(64) &&
+ (uint64_t(~Imm.getZExtValue()) & ~0xffULL) == 0;
+}], UIMM8, "U8Imm">;
+
+// Immediates for the 8-bit LSB chunk of an i16, with the other i16 bits
+// being one. The immediate is a 16-bit value held in an i64.
+defm imm16ll8c_i64 : Immediate<i64, [{
+ return Imm.isIntN(16) &&
+ (uint16_t(~Imm.getZExtValue()) & ~0xffULL) == 0;
+}], UIMM8, "U8Imm">;
+
+// Immediates for the 8-bit LSB chunk of an i32, with the other i32 bits
+// being one. The immediate is a 32-bit value held in an i64.
+defm imm32ll8c_i64 : Immediate<i64, [{
+ return Imm.isIntN(32) &&
+ (uint32_t(~Imm.getZExtValue()) & ~0xffULL) == 0;
+}], UIMM8, "U8Imm">;
+
defm imm64sx16 : Immediate<i64, [{
return Imm.isSignedIntN(16);
}], SIMM16, "S16Imm">;
@@ -681,6 +714,16 @@ def bdladdr12onlylen8 : BDLMode<"BDLAddr", "64", "12", "Only", "8">;
def bdraddr12only : BDRMode<"BDRAddr", "64", "12", "Only">;
def bdvaddr12only : BDVMode< "64", "12">;
+// 12-bit unsigned displacement variants (for NI, OI, XI)
+def bdaddr12off1 : ComplexPattern<i64, 2, "selectBDAddr12off1">;
+def bdaddr12off3 : ComplexPattern<i64, 2, "selectBDAddr12off3">;
+def bdaddr12off7 : ComplexPattern<i64, 2, "selectBDAddr12off7">;
+
+// 20-bit signed displacement variants (for NIY, OIY, XIY)
+def bdaddr20off1 : ComplexPattern<i64, 2, "selectBDAddr20off1">;
+def bdaddr20off3 : ComplexPattern<i64, 2, "selectBDAddr20off3">;
+def bdaddr20off7 : ComplexPattern<i64, 2, "selectBDAddr20off7">;
+
//===----------------------------------------------------------------------===//
// Miscellaneous
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/SystemZ/SystemZOperators.td b/llvm/lib/Target/SystemZ/SystemZOperators.td
index 739d9b2a7efb2..005b79638218a 100644
--- a/llvm/lib/Target/SystemZ/SystemZOperators.td
+++ b/llvm/lib/Target/SystemZ/SystemZOperators.td
@@ -1003,6 +1003,7 @@ class NonvolatileLoad<SDPatternOperator load>
def nonvolatile_anyextloadi8 : NonvolatileLoad<anyextloadi8>;
def nonvolatile_anyextloadi16 : NonvolatileLoad<anyextloadi16>;
def nonvolatile_anyextloadi32 : NonvolatileLoad<anyextloadi32>;
+def nonvolatile_load : NonvolatileLoad<load>;
// Non-volatile stores.
class NonvolatileStore<SDPatternOperator store>
@@ -1013,6 +1014,7 @@ class NonvolatileStore<SDPatternOperator store>
def nonvolatile_truncstorei8 : NonvolatileStore<truncstorei8>;
def nonvolatile_truncstorei16 : NonvolatileStore<truncstorei16>;
def nonvolatile_truncstorei32 : NonvolatileStore<truncstorei32>;
+def nonvolatile_store : NonvolatileStore<store>;
// A store of a load that can be implemented using MVC.
def mvc_store : PatFrag<(ops node:$value, node:$addr),
diff --git a/llvm/lib/Target/SystemZ/SystemZPatterns.td b/llvm/lib/Target/SystemZ/SystemZPatterns.td
index 4d6bc68e9a7ed..6d6d48083dd18 100644
--- a/llvm/lib/Target/SystemZ/SystemZPatterns.td
+++ b/llvm/lib/Target/SystemZ/SystemZPatterns.td
@@ -39,18 +39,51 @@ multiclass ZXB<SDPatternOperator operator, RegisterOperand cls,
// with LOAD, OPERATOR and STORE being the read, modify and write
// respectively. MODE is the addressing mode and IMM is the type
// of the second operand.
-class RMWI<SDPatternOperator load, SDPatternOperator operator,
- SDPatternOperator store, AddressingMode mode,
- PatFrag imm, Instruction insn>
- : Pat<(store (operator (load mode:$addr), imm:$src), mode:$addr),
- (insn mode:$addr, (UIMM8 imm:$src))>;
+class RMWI<ValueType vt, SDPatternOperator load, SDPatternOperator op,
+ SDPatternOperator store, ComplexPattern mode, PatFrag imm,
+ Instruction insn>
+ : Pat<(store (op (vt (load mode:$addr)), imm:$src), mode:$addr),
+ (insn mode:$addr, (UIMM8 $src))>;
// Record that INSN performs binary operation OPERATION on a byte
// memory location. IMM is the type of the second operand.
-multiclass RMWIByte<SDPatternOperator operator, AddressingMode mode,
- Instruction insn> {
- def : RMWI<z_anyextloadi8, operator, truncstorei8, mode, imm32, insn>;
- def : RMWI<z_anyextloadi8, operator, truncstorei8, mode, imm64, insn>;
+multiclass RMWIByte<SDPatternOperator operator, Instruction insn12,
+ Instruction insn20, PatFrag imm16Leaf = imm32zx8,
+ PatFrag imm32Leaf = imm32zx8,
+ PatFrag imm16Leaf64 = imm64zx8,
+ PatFrag imm32Leaf64 = imm64zx8,
+ PatFrag imm64Leaf = imm64zx8> {
+ // 12-bit displacement variants.
+ def : RMWI<i32, z_anyextloadi8, operator, truncstorei8, bdaddr12pair,
+ imm32zx8, insn12>;
+ def : RMWI<i64, z_anyextloadi8, operator, truncstorei8, bdaddr12pair,
+ imm64zx8, insn12>;
+ def : RMWI<i32, nonvolatile_anyextloadi16, operator,
+ nonvolatile_truncstorei16, bdaddr12off1, imm16Leaf, insn12>;
+ def : RMWI<i64, nonvolatile_anyextloadi16, operator,
+ nonvolatile_truncstorei16, bdaddr12off1, imm16Leaf64, insn12>;
+ def : RMWI<i32, nonvolatile_load, operator, nonvolatile_store,
+ bdaddr12off3, imm32Leaf, insn12>;
+ def : RMWI<i64, nonvolatile_anyextloadi32, operator,
+ nonvolatile_truncstorei32, bdaddr12off3, imm32Leaf64, insn12>;
+ def : RMWI<i64, nonvolatile_load, operator, nonvolatile_store,
+ bdaddr12off7, imm64Leaf, insn12>;
+
+ // 20-bit displacement variants.
+ def : RMWI<i32, z_anyextloadi8, operator, truncstorei8, bdaddr20pair,
+ imm32zx8, insn20>;
+ def : RMWI<i64, z_anyextloadi8, operator, truncstorei8, bdaddr20pair,
+ imm64zx8, insn20>;
+ def : RMWI<i32, nonvolatile_anyextloadi16, operator,
+ nonvolatile_truncstorei16, bdaddr20off1, imm16Leaf, insn20>;
+ def : RMWI<i64, nonvolatile_anyextloadi16, operator,
+ nonvolatile_truncstorei16, bdaddr20off1, imm16Leaf64, insn20>;
+ def : RMWI<i32, nonvolatile_load, operator, nonvolatile_store,
+ bdaddr20off3, imm32Leaf, insn20>;
+ def : RMWI<i64, nonvolatile_anyextloadi32, operator,
+ nonvolatile_truncstorei32, bdaddr20off3, imm32Leaf64, insn20>;
+ def : RMWI<i64, nonvolatile_load, operator, nonvolatile_store,
+ bdaddr20off7, imm64Leaf, insn20>;
}
// Record that INSN performs insertion TYPE into a register of class CLS.
diff --git a/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp b/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp
index 5353c36fd9b97..a0d4f32198126 100644
--- a/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZTargetTransformInfo.cpp
@@ -556,10 +556,32 @@ static bool isFoldableRMW(const Instruction *I, Type *Ty) {
switch (Opcode) {
case Instruction::And:
case Instruction::Or:
- case Instruction::Xor:
- if (BitWidth != 8)
+ case Instruction::Xor: {
+ if (BitWidth == 8)
+ break;
+ if (BitWidth != 16 && BitWidth != 32 && BitWidth != 64)
+ return false;
+
+ auto *CI = dyn_cast<ConstantInt>(I->getOperand(1));
+ if (!CI)
return false;
+
+ uint64_t Val = CI->getZExtValue();
+ if (Opcode == Instruction::And) {
+ if (BitWidth == 16 && (Val & 0xff00ULL) != 0xff00ULL)
+ return false;
+ if (BitWidth == 32 && (Val & 0xffffff00ULL) != 0xffffff00ULL)
+ return false;
+ if (BitWidth == 64 &&
+ (Val & 0xffffffffffffff00ULL) != 0xffffffffffffff00ULL)
+ return false;
+ } else {
+ if (CI->getValue().getActiveBits() > 8) {
+ return false;
+ }
+ }
break;
+ }
case Instruction::Add:
case Instruction::Sub:
if (BitWidth != 32 && BitWidth != 64)
diff --git a/llvm/test/Analysis/CostModel/SystemZ/fold-rmw-cost.ll b/llvm/test/Analysis/CostModel/SystemZ/fold-rmw-cost.ll
index 98aa0cda026d1..c4ef9734814cc 100644
--- a/llvm/test/Analysis/CostModel/SystemZ/fold-rmw-cost.ll
+++ b/llvm/test/Analysis/CostModel/SystemZ/fold-rmw-cost.ll
@@ -145,3 +145,168 @@ define void @test_vector_no_fold(<4 x i32> %val, ptr %p) {
ret void
}
+; Logical operations for i16/i32/i64 types.
+
+; Modifies only LSB bits.
+define void @test_and_i16_valid(ptr %p) {
+; CHECK-LABEL: 'test_and_i16_valid'
+; CHECK: cost of 0 {{.*}} and i16 %v, -255
+; CHECK: cost of 0 {{.*}} store i16
+ %v = load i16, ptr %p
+ %res = and i16 %v, 65281 ; 0xff01
+ store i16 %res, ptr %p
+ ret void
+}
+
+; Clears bit 8, just above LSB window.
+define void @test_and_i16_invalid_above(ptr %p) {
+; CHECK-LABEL: 'test_and_i16_invalid_above'
+; CHECK: cost of 1 {{.*}} and i16 %v, -511
+; CHECK: cost of 1 {{.*}} store i16
+ %v = load i16, ptr %p
+ %res = and i16 %v, 65025 ; 0xfe01
+ store i16 %res, ptr %p
+ ret void
+}
+
+; Active bits <=8.
+define void @test_or_i16_valid(ptr %p) {
+; CHECK-LABEL: 'test_or_i16_valid'
+; CHECK: cost of 0 {{.*}} or i16 %v, 255
+; CHECK: cost of 0 {{.*}} store i16
+ %v = load i16, ptr %p
+ %res = or i16 %v, 255 ; 0x00ff
+ store i16 %res, ptr %p
+ ret void
+}
+
+; Active bits > 8.
+define void @test_or_i16_invalid(ptr %p) {
+; CHECK-LABEL: 'test_or_i16_invalid'
+; CHECK: cost of 1 {{.*}} or i16 %v, 256
+; CHECK: cost of 1 {{.*}} store i16
+ %v = load i16, ptr %p
+ %res = or i16 %v, 256 ; 0x0100
+ store i16 %res, ptr %p
+ ret void
+}
+
+; Modifies only LSB bits.
+define void @test_and_i32_valid(ptr %p) {
+; CHECK-LABEL: 'test_and_i32_valid'
+; CHECK: cost of 0 {{.*}} and i32 %v, -255
+; CHECK: cost of 0 {{.*}} store i32
+ %v = load i32, ptr %p
+ %res = and i32 %v, 4294967041 ; 0xffffff01
+ store i32 %res, ptr %p
+ ret void
+}
+
+; Zero-extended i16 context.
+define void @test_and_i32_zext_invalid(ptr %p) {
+; CHECK-LABEL: 'test_and_i32_zext_invalid'
+; CHECK: cost of 1 {{.*}} and i32 %v, 65281
+; CHECK: cost of 1 {{.*}} store i32
+ %v = load i32, ptr %p
+ %res = and i32 %v, 65281 ; 0x0000ff01
+ store i32 %res, ptr %p
+ ret void
+}
+
+; One bit down from zero-extended threshold.
+define void @test_and_i32_zext_below_invalid(ptr %p) {
+; CHECK-LABEL: 'test_and_i32_zext_below_invalid'
+; CHECK: cost of 1 {{.*}} and i32 %v, 65025
+; CHECK: cost of 1 {{.*}} store i32
+ %v = load i32, ptr %p
+ %res = and i32 %v, 65025 ; 0x0000fe01
+ store i32 %res, ptr %p
+ ret void
+}
+
+; One bit above zero-extended threshold.
+define void @test_and_i32_zext_above_invalid(ptr %p) {
+; CHECK-LABEL: 'test_and_i32_zext_above_invalid'
+; CHECK: cost of 1 {{.*}} and i32 %v, 130817
+; CHECK: cost of 1 {{.*}} store i32
+ %v = load i32, ptr %p
+ %res = and i32 %v, 130817 ; 0x0001ff01
+ store i32 %res, ptr %p
+ ret void
+}
+
+; Modifies bits outside LSB.
+define void @test_and_i32_invalid(ptr %p) {
+; CHECK-LABEL: 'test_and_i32_invalid'
+; CHECK: cost of 1 {{.*}} and i32 %v, 16
+; CHECK: cost of 1 {{.*}} store i32
+ %v = load i32, ptr %p
+ %res = and i32 %v, 16
+ store i32 %res, ptr %p
+ ret void
+}
+
+; Active bits <=8.
+define void @test_xor_i32_valid(ptr %p) {
+; CHECK-LABEL: 'test_xor_i32_valid'
+; CHECK: cost of 0 {{.*}} xor i32 %v, 255
+; CHECK: cost of 0 {{.*}} store i32
+ %v = load i32, ptr %p
+ %res = xor i32 %v, 255 ; 0x000000ff
+ store i32 %res, ptr %p
+ ret void
+}
+
+; Active bits > 8.
+define void @test_xor_i32_invalid_above(ptr %p) {
+; CHECK-LABEL: 'test_xor_i32_invalid_above'
+; CHECK: cost of 1 {{.*}} xor i32 %v, 256
+; CHECK: cost of 1 {{.*}} store i32
+ %v = load i32, ptr %p
+ %res = xor i32 %v, 256 ; 0x00000100
+ store i32 %res, ptr %p
+ ret void
+}
+
+; Modifies only LSB bits.
+define void @test_and_i64_valid(ptr %p) {
+; CHECK-LABEL: 'test_and_i64_valid'
+; CHECK: cost of 0 {{.*}} and i64 %v, -255
+; CHECK: cost of 0 {{.*}} store i64
+ %v = load i64, ptr %p
+ %res = and i64 %v, -255 ; 0xffffffffffffff01
+ store i64 %res, ptr %p
+ ret void
+}
+
+; Clears bit 8.
+define void @test_and_i64_invalid_above(ptr %p) {
+; CHECK-LABEL: 'test_and_i64_invalid_above'
+; CHECK: cost of 1 {{.*}} and i64 %v, -511
+; CHECK: cost of 1 {{.*}} store i64
+ %v = load i64, ptr %p
+ %res = and i64 %v, -511 ; 0xfffffffffffffffe01
+ store i64 %res, ptr %p
+ ret void
+}
+
+; Active bits <=8.
+define void @test_or_i64_valid(ptr %p) {
+; CHECK-LABEL: 'test_or_i64_valid'
+; CHECK: cost of 0 {{.*}} or i64 %v, 255
+; CHECK: cost of 0 {{.*}} store i64
+ %v = load i64, ptr %p
+ %res = or i64 %v, 255 ; 0x00000000000000ff
+ store i64 %res, ptr %p
+ ret void
+}
+
+; Active bits > 8.
+define void @test_or_i64_invalid(ptr %p) {
+; CHECK-LABEL: 'test_or_i64_invalid'
+; CHECK: cost of 1 {{.*}} or i64 %v, 256
+ %v = load i64, ptr %p
+ %res = or i64 %v, 256 ; 0x0000000000000100
+ store i64 %res, ptr %p
+ ret void
+}
diff --git a/llvm/test/CodeGen/SystemZ/and-05.ll b/llvm/test/CodeGen/SystemZ/and-05.ll
index 5f28480966e10..42fa69d8e6983 100644
--- a/llvm/test/CodeGen/SystemZ/and-05.ll
+++ b/llvm/test/CodeGen/SystemZ/and-05.ll
@@ -2,7 +2,7 @@
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
-; Check the lowest useful constant, expressed as a signed integer.
+; Check the lowest useful constant for i8, expressed as a signed integer.
define void @f1(ptr %ptr) {
; CHECK-LABEL: f1:
; CHECK: ni 0(%r2), 1
@@ -13,7 +13,40 @@ define void @f1(ptr %ptr) {
ret void
}
-; Check the highest useful constant, expressed as a signed integer.
+; Check lowest useful constant for i16, expressed as a signed integer.
+define void @f1_i16(ptr %ptr) {
+; CHECK-LABEL: f1_i16:
+; CHECK: ni 1(%r2), 1
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, -255
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check lowest useful constant for i32, expressed as a signed integer.
+define void @f1_i32(ptr %ptr) {
+; CHECK-LABEL: f1_i32:
+; CHECK: ni 3(%r2), 1
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, -255
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check lowest useful constant for i64, expressed as a signed integer.
+define void @f1_i64(ptr %ptr) {
+; CHECK-LABEL: f1_i64:
+; CHECK: ni 7(%r2), 1
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -255
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i8, expressed as a signed integer.
define void @f2(ptr %ptr) {
; CHECK-LABEL: f2:
; CHECK: ni 0(%r2), 254
@@ -24,7 +57,51 @@ define void @f2(ptr %ptr) {
ret void
}
-; Check the lowest useful constant, expressed as an unsigned integer.
+; Check the highest useful constant for i16, expressed as a signed integer.
+define void @f2_i16(ptr %ptr) {
+; CHECK-LABEL: f2_i16:
+; CHECK: ni 1(%r2), 254
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, -2
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i32, expressed as a signed integer.
+define void @f2_i32(ptr %ptr) {
+; CHECK-LABEL: f2_i32:
+; CHECK: ni 3(%r2), 254
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, -2
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check i32 with zero-extended i16 pattern (0x0000FFxx).
+define void @f2_i32_zext(ptr %ptr) {
+; CHECK-LABEL: f2_i32_zext:
+; CHECK: n %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 65534 ; 0x0000FFFE
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i64, expressed as a signed integer.
+define void @f2_i64(ptr %ptr) {
+; CHECK-LABEL: f2_i64:
+; CHECK: ni 7(%r2), 254
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -2
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check the lowest useful constant for i8, expressed as an unsigned integer.
define void @f3(ptr %ptr) {
; CHECK-LABEL: f3:
; CHECK: ni 0(%r2), 1
@@ -35,6 +112,51 @@ define void @f3(ptr %ptr) {
ret void
}
+; Check the lowest useful constant for i16, expressed as an unsigned integer.
+; Constant 1 should not fold for i16, as it requires clearing the high byte.
+define void @f3_i16(ptr %ptr) {
+; CHECK-LABEL: f3_i16:
+; CHECK-NOT: ni 1(%r2), 1
+; CHECK: llh %r0, 0(%r2)
+; CHECK: nilf %r0, 1
+; CHECK: sth %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 1
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the lowest useful constant for i32, expressed as an unsigned integer.
+; Constant 1 should not fold for i32, as it requires clearing the high bytes.
+define void @f3_i32(ptr %ptr) {
+; CHECK-LABEL: f3_i32:
+; CHECK-NOT: ni 3(%r2), 1
+; CHECK: lhi %r0, 1
+; CHECK: n %r0, 0(%r2)
+; CHECK: st %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 1
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the lowest useful constant for i64, expressed as an unsigned integer.
+; Constant 1 should not fold for i64, as it requires clearing the high bytes.
+define void @f3_i64(ptr %ptr) {
+; CHECK-LABEL: f3_i64:
+; CHECK-NOT: ni 7(%r2), 1
+; CHECK: lg %r0, 0(%r2)
+; CHECK: risbg %r0, %r0, 63, 191, 0
+; CHECK: stg %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, 1
+ store i64 %and, ptr %ptr
+ ret void
+}
+
; Check the highest useful constant, expressed as a unsigned integer.
define void @f4(ptr %ptr) {
; CHECK-LABEL: f4:
@@ -46,7 +168,53 @@ define void @f4(ptr %ptr) {
ret void
}
-; Check the high end of the NI range.
+; Check the highest useful constant for i16, expressed as a unsigned integer.
+; Constant 254 (0x00FE) should not fold for i16 because the high byte must be
+; cleared.
+define void @f4_i16(ptr %ptr) {
+; CHECK-LABEL: f4_i16:
+; CHECK-NOT: ni 1(%r2), 254
+; CHECK: llh %r0, 0(%r2)
+; CHECK: nilf %r0, 254
+; CHECK: sth %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 254
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i32, expressed as a unsigned integer.
+; Constant 254 should not fold for i32 because the high byte must be cleared.
+define void @f4_i32(ptr %ptr) {
+; CHECK-LABEL: f4_i32:
+; CHECK-NOT: ni 3(%r2), 254
+; CHECK: lhi %r0, 254
+; CHECK: n %r0, 0(%r2)
+; CHECK: st %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 254
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i64, expressed as a unsigned integer.
+; Constant 254 should not fold for i64 because the high byte must be cleared.
+define void @f4_i64(ptr %ptr) {
+; CHECK-LABEL: f4_i64:
+; CHECK-NOT: ni 7(%r2), 254
+; CHECK: lg %r0, 0(%r2)
+; CHECK: risbg %r0, %r0, 56, 190, 0
+; CHECK: stg %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, 254
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check the high end of the NI range for i8.
define void @f5(ptr %src) {
; CHECK-LABEL: f5:
; CHECK: ni 4095(%r2), 127
@@ -58,7 +226,43 @@ define void @f5(ptr %src) {
ret void
}
-; Check the next byte up, which should use NIY instead of NI.
+; Check the high end of the NI range for i16.
+define void @f5_i16(ptr %src) {
+; CHECK-LABEL: f5_i16:
+; CHECK: ni 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4094
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the high end of the NI range for i32.
+define void @f5_i32(ptr %src) {
+; CHECK-LABEL: f5_i32:
+; CHECK: ni 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4092
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the high end of the NI range for i64.
+define void @f5_i64(ptr %src) {
+; CHECK-LABEL: f5_i64:
+; CHECK: ni 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4088
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -129
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i8, which should use NIY instead of NI.
define void @f6(ptr %src) {
; CHECK-LABEL: f6:
; CHECK: niy 4096(%r2), 127
@@ -70,7 +274,43 @@ define void @f6(ptr %src) {
ret void
}
-; Check the high end of the NIY range.
+; Check the next byte up for i16, which should use NIY instead of NI.
+define void @f6_i16(ptr %src) {
+; CHECK-LABEL: f6_i16:
+; CHECK: niy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4095
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i32, which should use NIY instead of NI.
+define void @f6_i32(ptr %src) {
+; CHECK-LABEL: f6_i32:
+; CHECK: niy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4093
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i64, which should use NIY instead of NI.
+define void @f6_i64(ptr %src) {
+; CHECK-LABEL: f6_i64:
+; CHECK: niy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4089
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -129
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check the high end of the NIY range for i8.
define void @f7(ptr %src) {
; CHECK-LABEL: f7:
; CHECK: niy 524287(%r2), 127
@@ -82,7 +322,43 @@ define void @f7(ptr %src) {
ret void
}
-; Check the next byte up, which needs separate address logic.
+; Check the high end of the NIY range for i16.
+define void @f7_i16(ptr %src) {
+; CHECK-LABEL: f7_i16:
+; CHECK: niy 524287(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524286
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the high end of the NIY range for i32.
+define void @f7_i32(ptr %src) {
+; CHECK-LABEL: f7_i32:
+; CHECK: niy 524287(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524284
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the high end of the NIY range for i64.
+define void @f7_i64(ptr %src) {
+; CHECK-LABEL: f7_i64:
+; CHECK: niy 524287(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524280
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -129
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i8, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f8(ptr %src) {
; CHECK-LABEL: f8:
@@ -96,7 +372,49 @@ define void @f8(ptr %src) {
ret void
}
-; Check the high end of the negative NIY range.
+; Check the next byte up for i16, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f8_i16(ptr %src) {
+; CHECK-LABEL: f8_i16:
+; CHECK: agfi %r2, 524288
+; CHECK: ni 1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524288
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i32, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f8_i32(ptr %src) {
+; CHECK-LABEL: f8_i32:
+; CHECK: agfi %r2, 524288
+; CHECK: ni 3(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524288
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i64, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f8_i64(ptr %src) {
+; CHECK-LABEL: f8_i64:
+; CHECK: agfi %r2, 524288
+; CHECK: ni 7(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524288
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -129
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check the high end of the negative NIY range for i8.
define void @f9(ptr %src) {
; CHECK-LABEL: f9:
; CHECK: niy -1(%r2), 127
@@ -108,7 +426,43 @@ define void @f9(ptr %src) {
ret void
}
-; Check the low end of the NIY range.
+; Check the high end of the negative NIY range for i16.
+define void @f9_i16(ptr %src) {
+; CHECK-LABEL: f9_i16:
+; CHECK: niy -1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -2
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the high end of the negative NIY range for i32.
+define void @f9_i32(ptr %src) {
+; CHECK-LABEL: f9_i32:
+; CHECK: niy -1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -4
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the high end of the negative NIY range for i64.
+define void @f9_i64(ptr %src) {
+; CHECK-LABEL: f9_i64:
+; CHECK: niy -1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -8
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -129
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check the low end of the NIY range for i8.
define void @f10(ptr %src) {
; CHECK-LABEL: f10:
; CHECK: niy -524288(%r2), 127
@@ -120,7 +474,43 @@ define void @f10(ptr %src) {
ret void
}
-; Check the next byte down, which needs separate address logic.
+; Check the low end of the NIY range for i16.
+define void @f10_i16(ptr %src) {
+; CHECK-LABEL: f10_i16:
+; CHECK: niy -524288(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524289
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the low end of the NIY range for i32.
+define void @f10_i32(ptr %src) {
+; CHECK-LABEL: f10_i32:
+; CHECK: niy -524288(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524291
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the low end of the NIY range for i64.
+define void @f10_i64(ptr %src) {
+; CHECK-LABEL: f10_i64:
+; CHECK: niy -524288(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524295
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -129
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check the next byte down for i8, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f11(ptr %src) {
; CHECK-LABEL: f11:
@@ -134,7 +524,49 @@ define void @f11(ptr %src) {
ret void
}
-; Check that NI does not allow an index
+; Check the next byte down for i16, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f11_i16(ptr %src) {
+; CHECK-LABEL: f11_i16:
+; CHECK: agfi %r2, -524290
+; CHECK: ni 1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524290
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the next byte down for i32, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f11_i32(ptr %src) {
+; CHECK-LABEL: f11_i32:
+; CHECK: agfi %r2, -524292
+; CHECK: ni 3(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524292
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the next byte down for i64, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f11_i64(ptr %src) {
+; CHECK-LABEL: f11_i64:
+; CHECK: agfi %r2, -524296
+; CHECK: ni 7(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524296
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -129
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check that NI does not allow an index for i8.
define void @f12(i64 %src, i64 %index) {
; CHECK-LABEL: f12:
; CHECK: agr %r2, %r3
@@ -149,7 +581,52 @@ define void @f12(i64 %src, i64 %index) {
ret void
}
-; Check that NIY does not allow an index
+; Check that NI does not allow an index for i16.
+define void @f12_i16(i64 %src, i64 %index) {
+; CHECK-LABEL: f12_i16:
+; CHECK: agr %r2, %r3
+; CHECK: ni 4095(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4094
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the NI does not allow an index for i32.
+define void @f12_i32(i64 %src, i64 %index) {
+; CHECK-LABEL: f12_i32:
+; CHECK: agr %r2, %r3
+; CHECK: ni 4095(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4092
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the NI does not allow an index for i64.
+define void @f12_i64(i64 %src, i64 %index) {
+; CHECK-LABEL: f12_i64:
+; CHECK: agr %r2, %r3
+; CHECK: ni 4095(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4088
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -129
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check that NIY does not allow an index for i8.
define void @f13(i64 %src, i64 %index) {
; CHECK-LABEL: f13:
; CHECK: agr %r2, %r3
@@ -163,3 +640,263 @@ define void @f13(i64 %src, i64 %index) {
store i8 %and, ptr %ptr
ret void
}
+
+; Check the NIY does not allow an index for i16.
+define void @f13_i16(i64 %src, i64 %index) {
+; CHECK-LABEL: f13_i16:
+; CHECK: agr %r2, %r3
+; CHECK: niy 4096(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4095
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check the NIY does not allow an index for i32.
+define void @f13_i32(i64 %src, i64 %index) {
+; CHECK-LABEL: f13_i32:
+; CHECK: agr %r2, %r3
+; CHECK: niy 4096(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4093
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check the NIY does not allow an index for i64.
+define void @f13_i64(i64 %src, i64 %index) {
+; CHECK-LABEL: f13_i64:
+; CHECK: agr %r2, %r3
+; CHECK: niy 4096(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4089
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -129
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check NI with a i64 intermediate value for an i16.
+define void @f14_i16(ptr %src) {
+; CHECK-LABEL: f14_i16:
+; CHECK: ni 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4094
+ %val = load i16, ptr %ptr
+ %ext = zext i16 %val to i64
+ %and = and i64 %ext, 65407
+ %tr = trunc i64 %and to i16
+ store i16 %tr, ptr %ptr
+ ret void
+}
+
+; Check NI with a i64 intermediate value for an i32.
+define void @f14_i32(ptr %src) {
+; CHECK-LABEL: f14_i32:
+; CHECK: ni 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4092
+ %val = load i32, ptr %ptr
+ %ext = zext i32 %val to i64
+ %and = and i64 %ext, 4294967167
+ %tr = trunc i64 %and to i32
+ store i32 %tr, ptr %ptr
+ ret void
+}
+
+; Check NIY with a i64 intermediate value for an i16.
+define void @f15_i16(ptr %src) {
+; CHECK-LABEL: f15_i16:
+; CHECK: niy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4095
+ %val = load i16, ptr %ptr
+ %ext = zext i16 %val to i64
+ %and = and i64 %ext, 65407
+ %tr = trunc i64 %and to i16
+ store i16 %tr, ptr %ptr
+ ret void
+}
+
+; Check NIY with a i64 intermediate value for an i32.
+define void @f15_i32(ptr %src) {
+; CHECK-LABEL: f15_i32:
+; CHECK: niy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4093
+ %val = load i32, ptr %ptr
+ %ext = zext i32 %val to i64
+ %and = and i64 %ext, 4294967167
+ %tr = trunc i64 %and to i32
+ store i32 %tr, ptr %ptr
+ ret void
+}
+
+; Check volatile i16 load/store with AND is not folded.
+define void @f16_i16(ptr %ptr) {
+; CHECK-LABEL: f16_i16:
+; CHECK: llh [[REG:%r[0-5]]], 0(%r2)
+; CHECK-NEXT: nill [[REG]], 65407
+; CHECK-NOT: ni
+; CHECK-NOT: niy
+; CHECK: br %r14
+ %val = load volatile i16, ptr %ptr
+ %and = and i16 %val, 65407
+ store volatile i16 %and, ptr %ptr
+ ret void
+}
+
+; Check volatile i32 load/store with AND is not folded.
+define void @f16_i32(ptr %ptr) {
+; CHECK-LABEL: f16_i32:
+; CHECK: n [[REG:%r[0-5]]], 0(%r2)
+; CHECK-NOT: ni
+; CHECK-NOT: niy
+; CHECK: br %r14
+ %val = load volatile i32, ptr %ptr
+ %and = and i32 %val, 4294967167
+ store volatile i32 %and, ptr %ptr
+ ret void
+}
+
+; Check volatile i64 load/store with AND is not folded.
+define void @f16_i64(ptr %ptr) {
+; CHECK-LABEL: f16_i64:
+; CHECK: ng [[REG:%r[0-5]]], 0(%r2)
+; CHECK-NOT: ni
+; CHECK-NOT: niy
+; CHECK: br %r14
+ %val = load volatile i64, ptr %ptr
+ %and = and i64 %val, -129
+ store volatile i64 %and, ptr %ptr
+ ret void
+}
+
+; Check folding of multi-byte 'and' operations into byte-immediate memory
+; operation 'ni'.
+; Additional tests for immAndLSB8 PatLeaf logic - preservation of upper bytes
+; for i16, i32, and i64. Low/high constant (signed/unsigned) tests have already
+; been covered (f1 to f4).
+
+; Check i16 - should not fold. High byte has bit cleared.
+define void @f_const_i16_no_fold(ptr %ptr) {
+; CHECK-LABEL: f_const_i16_no_fold:
+; CHECK-NOT: ni 1(%r2)
+; CHECK: llh [[REG:%r[0-5]]], 0(%r2)
+; CHECK: nilf [[REG]], 65278
+; CHECK: sth [[REG]], 0(%r2)
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65278 ; 0xFEFE
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check i32 - should not fold. Upper bytes have bit cleared.
+define void @f_const_i32_no_fold(ptr %ptr) {
+; CHECK-LABEL: f_const_i32_no_fold:
+; CHECK-NOT: ni 3(%r2)
+; CHECK: lhi [[REG:%r[0-5]]], -258
+; CHECK: n [[REG]], 0(%r2)
+; CHECK: st [[REG]], 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294967038 ; 0xFFFFFEFE
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check i64 - should not fold. Upper bytes have bit cleared.
+define void @f_const_i64_no_fold(ptr %ptr) {
+; CHECK-LABEL: f_const_i64_no_fold:
+; CHECK-NOT: ni 7(%r2)
+; CHECK: lghi [[REG:%r[0-5]]], -258
+; CHECK: ng [[REG]], 0(%r2)
+; CHECK: stg [[REG]], 0(%r2)
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -258 ; 0xFFFFFFFFFFFFFFFE
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check i16 - should not fold. Constant 0xFE00 affects more than just the LSB.
+define void @f_const_i16_multi_byte_no_fold(ptr %ptr) {
+; CHECK-LABEL: f_const_i16_multi_byte_no_fold:
+; CHECK-NOT: ni 1(%r2)
+; CHECK: llh [[REG:%r[0-5]]], 0(%r2)
+; CHECK: nilf [[REG]], 65024
+; CHECK: sth [[REG]], 0(%r2)
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %and = and i16 %val, 65024 ; 0xFE00
+ store i16 %and, ptr %ptr
+ ret void
+}
+
+; Check i32 - should not fold. Constant 0xFFFFFE00 affects more than just the
+; LSB.
+define void @f_const_i32_multi_byte_no_fold(ptr %ptr) {
+; CHECK-LABEL: f_const_i32_multi_byte_no_fold:
+; CHECK-NOT: ni 3(%r2)
+; CHECK: lhi %r0, -512
+; CHECK: n %r0, 0(%r2)
+; CHECK: st %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294966784 ; 0xFFFFFE00
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check i32 - should not fold. Constant affects a non-LSB byte.
+define void @f_const_i32_wrong_byte_no_fold(ptr %ptr) {
+; CHECK-LABEL: f_const_i32_wrong_byte_no_fold:
+; CHECK-NOT: ni 3(%r2)
+; CHECK: iilf [[REG:%r[0-5]]], 4294902015
+; CHECK: n [[REG]], 0(%r2)
+; CHECK: st [[REG]], 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %and = and i32 %val, 4294902015 ; 0xFFFF00FF
+ store i32 %and, ptr %ptr
+ ret void
+}
+
+; Check i64 - should not fold. Constant affects more than just the LSB.
+define void @f_const_i64_multi_byte_no_fold(ptr %ptr) {
+; CHECK-LABEL: f_const_i64_multi_byte_no_fold:
+; CHECK-NOT: ni 7(%r2)
+; CHECK: lghi [[REG:%r[0-5]]], -512
+; CHECK: ng [[REG]], 0(%r2)
+; CHECK: stg [[REG]], 0(%r2)
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -512 ; 0xFFFFFFFFFFFFFE00
+ store i64 %and, ptr %ptr
+ ret void
+}
+
+; Check i64 - should not fold. Constant affects a non-LSB byte.
+define void @f_const_i64_wrong_byte_no_fold(ptr %ptr) {
+; CHECK-LABEL: f_const_i64_wrong_byte_no_fold:
+; CHECK-NOT: ni 7(%r2)
+; CHECK: lgfi [[REG:%r[0-5]]], -65281
+; CHECK: ng [[REG]], 0(%r2)
+; CHECK: stg [[REG]], 0(%r2)
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %and = and i64 %val, -65281 ; 0xFFFFFFFFFFFF00FF
+ store i64 %and, ptr %ptr
+ ret void
+}
diff --git a/llvm/test/CodeGen/SystemZ/or-05.ll b/llvm/test/CodeGen/SystemZ/or-05.ll
index 6ec352fa7b419..c1b43adb59a91 100644
--- a/llvm/test/CodeGen/SystemZ/or-05.ll
+++ b/llvm/test/CodeGen/SystemZ/or-05.ll
@@ -2,7 +2,7 @@
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
-; Check the lowest useful constant, expressed as a signed integer.
+; Check the lowest useful constant for i8, expressed as a signed integer.
define void @f1(ptr %ptr) {
; CHECK-LABEL: f1:
; CHECK: oi 0(%r2), 1
@@ -13,7 +13,49 @@ define void @f1(ptr %ptr) {
ret void
}
-; Check the highest useful constant, expressed as a signed integer.
+; Check lowest useful constant for i16, expressed as a signed integer.
+define void @f1_i16(ptr %ptr) {
+; CHECK-LABEL: f1_i16:
+; CHECK-NOT: oi 1(%r2)
+; CHECK: lh %r0, 0(%r2)
+; CHECK: oill %r0, 65281
+; CHECK: sth %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, -255
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check lowest useful constant for i32, expressed as a signed integer.
+define void @f1_i32(ptr %ptr) {
+; CHECK-LABEL: f1_i32:
+; CHECK-NOT: oi 3(%r2)
+; CHECK: lhi %r0, -255
+; CHECK: o %r0, 0(%r2)
+; CHECK: st %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, -255
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check lowest useful constant for i64, expressed as a signed integer.
+define void @f1_i64(ptr %ptr) {
+; CHECK-LABEL: f1_i64:
+; CHECK-NOT: oi 7(%r2)
+; CHECK: lg {{%r[0-9]+}}, 0(%r2)
+; CHECK: oihf %r0, 4294967295
+; CHECK: stg {{%r[0-9]+}}, 0(%r2)
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, -255
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i8, expressed as a signed integer.
define void @f2(ptr %ptr) {
; CHECK-LABEL: f2:
; CHECK: oi 0(%r2), 254
@@ -24,7 +66,47 @@ define void @f2(ptr %ptr) {
ret void
}
-; Check the lowest useful constant, expressed as an unsigned integer.
+; Check the highest useful constant for i16, expressed as a signed integer.
+define void @f2_i16(ptr %ptr) {
+; CHECK-LABEL: f2_i16:
+; CHECK-NOT: oi 1(%r2), 254
+; CHECK: lh %r0, 0(%r2)
+; CHECK: oill %r0, 65534
+; CHECK: sth %r0, 0(%r2)
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, -2
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i32, expressed as a signed integer.
+define void @f2_i32(ptr %ptr) {
+; CHECK-LABEL: f2_i32:
+; CHECK-NOT: oi 3(%r2)
+; CHECK: lhi %r0, -2
+; CHECK: o %r0, 0(%r2)
+; CHECK: st %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, -2
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i64, expressed as a signed integer.
+define void @f2_i64(ptr %ptr) {
+; CHECK-LABEL: f2_i64:
+; CHECK-NOT: oi 7(%r2)
+; CHECK: lg [[REG:%r[0-9]+]], 0(%r2)
+; CHECK: oilf [[REG]], 4294967294
+; CHECK: stg [[REG]], 0(%r2)
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, -2
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the lowest useful constant for i8, expressed as an unsigned integer.
define void @f3(ptr %ptr) {
; CHECK-LABEL: f3:
; CHECK: oi 0(%r2), 1
@@ -35,7 +117,40 @@ define void @f3(ptr %ptr) {
ret void
}
-; Check the highest useful constant, expressed as a unsigned integer.
+; Check the lowest useful constant for i16, expressed as an unsigned integer.
+define void @f3_i16(ptr %ptr) {
+; CHECK-LABEL: f3_i16:
+; CHECK: oi 1(%r2), 1
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 1
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the lowest useful constant for i32, expressed as an unsigned integer.
+define void @f3_i32(ptr %ptr) {
+; CHECK-LABEL: f3_i32:
+; CHECK: oi 3(%r2), 1
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 1
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the lowest useful constant for i64, expressed as an unsigned integer.
+define void @f3_i64(ptr %ptr) {
+; CHECK-LABEL: f3_i64:
+; CHECK: oi 7(%r2), 1
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 1
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant i8, expressed as a unsigned integer.
define void @f4(ptr %ptr) {
; CHECK-LABEL: f4:
; CHECK: oi 0(%r2), 254
@@ -46,7 +161,40 @@ define void @f4(ptr %ptr) {
ret void
}
-; Check the high end of the OI range.
+; Check the highest useful constant for i16, expressed as a unsigned integer.
+define void @f4_i16(ptr %ptr) {
+; CHECK-LABEL: f4_i16:
+; CHECK: oi 1(%r2), 254
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 254
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i32, expressed as a unsigned integer.
+define void @f4_i32(ptr %ptr) {
+; CHECK-LABEL: f4_i32:
+; CHECK: oi 3(%r2), 254
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 254
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i64, expressed as a unsigned integer.
+define void @f4_i64(ptr %ptr) {
+; CHECK-LABEL: f4_i64:
+; CHECK: oi 7(%r2), 254
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 254
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the high end of the OI range for i8.
define void @f5(ptr %src) {
; CHECK-LABEL: f5:
; CHECK: oi 4095(%r2), 127
@@ -58,7 +206,43 @@ define void @f5(ptr %src) {
ret void
}
-; Check the next byte up, which should use OIY instead of OI.
+; Check the high end of the OI range for i16.
+define void @f5_i16(ptr %src) {
+; CHECK-LABEL: f5_i16:
+; CHECK: oi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4094
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 127
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the high end of the OI range for i32.
+define void @f5_i32(ptr %src) {
+; CHECK-LABEL: f5_i32:
+; CHECK: oi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4092
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 127
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the high end of the OI range for i64.
+define void @f5_i64(ptr %src) {
+; CHECK-LABEL: f5_i64:
+; CHECK: oi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4088
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 127
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i8, which should use OIY instead of OI.
define void @f6(ptr %src) {
; CHECK-LABEL: f6:
; CHECK: oiy 4096(%r2), 127
@@ -70,7 +254,43 @@ define void @f6(ptr %src) {
ret void
}
-; Check the high end of the OIY range.
+; Check the next byte up for i16, which should use OIY instead of OI.
+define void @f6_i16(ptr %src) {
+; CHECK-LABEL: f6_i16:
+; CHECK: oiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4095
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 127
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i32, which should use OIY instead of OI.
+define void @f6_i32(ptr %src) {
+; CHECK-LABEL: f6_i32:
+; CHECK: oiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4093
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 127
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i64, which should use OIY instead of OI.
+define void @f6_i64(ptr %src) {
+; CHECK-LABEL: f6_i64:
+; CHECK: oiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4089
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 127
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the high end of the OIY range for i8.
define void @f7(ptr %src) {
; CHECK-LABEL: f7:
; CHECK: oiy 524287(%r2), 127
@@ -82,7 +302,43 @@ define void @f7(ptr %src) {
ret void
}
-; Check the next byte up, which needs separate address logic.
+; Check the high end of the OIY range for i16.
+define void @f7_i16(ptr %src) {
+; CHECK-LABEL: f7_i16:
+; CHECK: oiy 524287(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524286
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 127
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the high end of the OIY range for i32.
+define void @f7_i32(ptr %src) {
+; CHECK-LABEL: f7_i32:
+; CHECK: oiy 524287(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524284
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 127
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the high end of the OIY range for i64.
+define void @f7_i64(ptr %src) {
+; CHECK-LABEL: f7_i64:
+; CHECK: oiy 524287(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524280
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 127
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i8, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f8(ptr %src) {
; CHECK-LABEL: f8:
@@ -96,7 +352,49 @@ define void @f8(ptr %src) {
ret void
}
-; Check the high end of the negative OIY range.
+; Check the next byte up for i16, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f8_i16(ptr %src) {
+; CHECK-LABEL: f8_i16:
+; CHECK: agfi %r2, 524288
+; CHECK: oi 1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524288
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 127
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i32, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f8_i32(ptr %src) {
+; CHECK-LABEL: f8_i32:
+; CHECK: agfi %r2, 524288
+; CHECK: oi 3(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524288
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 127
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i64, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f8_i64(ptr %src) {
+; CHECK-LABEL: f8_i64:
+; CHECK: agfi %r2, 524288
+; CHECK: oi 7(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524288
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 127
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the high end of the negative OIY range for i8.
define void @f9(ptr %src) {
; CHECK-LABEL: f9:
; CHECK: oiy -1(%r2), 127
@@ -108,7 +406,43 @@ define void @f9(ptr %src) {
ret void
}
-; Check the low end of the OIY range.
+; Check the high end of the negative OIY range for i16.
+define void @f9_i16(ptr %src) {
+; CHECK-LABEL: f9_i16:
+; CHECK: oiy -1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -2
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 127
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the high end of the negative OIY range for i32.
+define void @f9_i32(ptr %src) {
+; CHECK-LABEL: f9_i32:
+; CHECK: oiy -1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -4
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 127
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the high end of the negative OIY range for i64.
+define void @f9_i64(ptr %src) {
+; CHECK-LABEL: f9_i64:
+; CHECK: oiy -1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -8
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 127
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the low end of the OIY range for i8.
define void @f10(ptr %src) {
; CHECK-LABEL: f10:
; CHECK: oiy -524288(%r2), 127
@@ -120,7 +454,43 @@ define void @f10(ptr %src) {
ret void
}
-; Check the next byte down, which needs separate address logic.
+; Check the low end of the OIY range for i16.
+define void @f10_i16(ptr %src) {
+; CHECK-LABEL: f10_i16:
+; CHECK: oiy -524288(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524289
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 127
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the low end of the OIY range for i32.
+define void @f10_i32(ptr %src) {
+; CHECK-LABEL: f10_i32:
+; CHECK: oiy -524288(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524291
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 127
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the low end of the OIY range for i64.
+define void @f10_i64(ptr %src) {
+; CHECK-LABEL: f10_i64:
+; CHECK: oiy -524288(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524295
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 127
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check the next byte down for i8, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f11(ptr %src) {
; CHECK-LABEL: f11:
@@ -134,7 +504,49 @@ define void @f11(ptr %src) {
ret void
}
-; Check that OI does not allow an index
+; Check the next byte down for i16, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f11_i16(ptr %src) {
+; CHECK-LABEL: f11_i16:
+; CHECK: agfi %r2, -524290
+; CHECK: oi 1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524290
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 127
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the next byte down for i32, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f11_i32(ptr %src) {
+; CHECK-LABEL: f11_i32:
+; CHECK: agfi %r2, -524292
+; CHECK: oi 3(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524292
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 127
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the next byte down for i64, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f11_i64(ptr %src) {
+; CHECK-LABEL: f11_i64:
+; CHECK: agfi %r2, -524296
+; CHECK: oi 7(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524296
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 127
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check that OI does not allow an index for i8.
define void @f12(i64 %src, i64 %index) {
; CHECK-LABEL: f12:
; CHECK: agr %r2, %r3
@@ -149,7 +561,52 @@ define void @f12(i64 %src, i64 %index) {
ret void
}
-; Check that OIY does not allow an index
+; Check the OI does not allow an index for i16.
+define void @f12_i16(i64 %src, i64 %index) {
+; CHECK-LABEL: f12_i16:
+; CHECK: agr %r2, %r3
+; CHECK: oi 4095(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4094
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 127
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the OI does not allow an index for i32.
+define void @f12_i32(i64 %src, i64 %index) {
+; CHECK-LABEL: f12_i32:
+; CHECK: agr %r2, %r3
+; CHECK: oi 4095(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4092
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 127
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the OI does not allow an index for i64.
+define void @f12_i64(i64 %src, i64 %index) {
+; CHECK-LABEL: f12_i64:
+; CHECK: agr %r2, %r3
+; CHECK: oi 4095(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4088
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 127
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check that OIY does not allow an index for i8.
define void @f13(i64 %src, i64 %index) {
; CHECK-LABEL: f13:
; CHECK: agr %r2, %r3
@@ -163,3 +620,144 @@ define void @f13(i64 %src, i64 %index) {
store i8 %or, ptr %ptr
ret void
}
+
+; Check the OIY does not allow an index for i16.
+define void @f13_i16(i64 %src, i64 %index) {
+; CHECK-LABEL: f13_i16:
+; CHECK: agr %r2, %r3
+; CHECK: oiy 4096(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4095
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i16, ptr %ptr
+ %or = or i16 %val, 127
+ store i16 %or, ptr %ptr
+ ret void
+}
+
+; Check the OIY does not allow an index for i32.
+define void @f13_i32(i64 %src, i64 %index) {
+; CHECK-LABEL: f13_i32:
+; CHECK: agr %r2, %r3
+; CHECK: oiy 4096(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4093
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i32, ptr %ptr
+ %or = or i32 %val, 127
+ store i32 %or, ptr %ptr
+ ret void
+}
+
+; Check the OIY does not allow an index for i64.
+define void @f13_i64(i64 %src, i64 %index) {
+; CHECK-LABEL: f13_i64:
+; CHECK: agr %r2, %r3
+; CHECK: oiy 4096(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4089
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i64, ptr %ptr
+ %or = or i64 %val, 127
+ store i64 %or, ptr %ptr
+ ret void
+}
+
+; Check OI with a i64 intermediate value for an i16.
+define void @f14_i16(ptr %src) {
+; CHECK-LABEL: f14_i16:
+; CHECK: oi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4094
+ %val = load i16, ptr %ptr
+ %ext = zext i16 %val to i64
+ %or = or i64 %ext, 127
+ %tr = trunc i64 %or to i16
+ store i16 %tr, ptr %ptr
+ ret void
+}
+
+; Check OI with a i64 intermediate value for an i32.
+define void @f14_i32(ptr %src) {
+; CHECK-LABEL: f14_i32:
+; CHECK: oi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4092
+ %val = load i32, ptr %ptr
+ %ext = zext i32 %val to i64
+ %or = or i64 %ext, 127
+ %tr = trunc i64 %or to i32
+ store i32 %tr, ptr %ptr
+ ret void
+}
+
+; Check OIY with a i64 intermediate value for an i16.
+define void @f15_i16(ptr %src) {
+; CHECK-LABEL: f15_i16:
+; CHECK: oiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4095
+ %val = load i16, ptr %ptr
+ %ext = zext i16 %val to i64
+ %or = or i64 %ext, 127
+ %tr = trunc i64 %or to i16
+ store i16 %tr, ptr %ptr
+ ret void
+}
+
+; Check OIY with a i64 intermediate value for an i32.
+define void @f15_i32(ptr %src) {
+; CHECK-LABEL: f15_i32:
+; CHECK: oiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4093
+ %val = load i32, ptr %ptr
+ %ext = zext i32 %val to i64
+ %or = or i64 %ext, 127
+ %tr = trunc i64 %or to i32
+ store i32 %tr, ptr %ptr
+ ret void
+}
+
+; Check volatile i16 load/store with OR is not folded.
+define void @f16_i16(ptr %ptr) {
+; CHECK-LABEL: f16_i16:
+; CHECK: lh [[REG:%r[0-5]]], 0(%r2)
+; CHECK-NEXT: oill [[REG]], 128
+; CHECK-NOT: oi
+; CHECK-NOT: oiy
+; CHECK: br %r14
+ %val = load volatile i16, ptr %ptr
+ %or = or i16 %val, 128
+ store volatile i16 %or, ptr %ptr
+ ret void
+}
+
+; Check volatile i32 load/store with OR is not folded.
+define void @f16_i32(ptr %ptr) {
+; CHECK-LABEL: f16_i32:
+; CHECK: o [[REG:%r[0-5]]], 0(%r2)
+; CHECK-NOT: oi
+; CHECK-NOT: oiy
+; CHECK: br %r14
+ %val = load volatile i32, ptr %ptr
+ %or = or i32 %val, 128
+ store volatile i32 %or, ptr %ptr
+ ret void
+}
+
+; Check volatile i64 load/store with OR is not folded.
+define void @f16_i64(ptr %ptr) {
+; CHECK-LABEL: f16_i64:
+; CHECK: og [[REG:%r[0-5]]], 0(%r2)
+; CHECK-NOT: oi
+; CHECK-NOT: oiy
+; CHECK: br %r14
+ %val = load volatile i64, ptr %ptr
+ %or = or i64 %val, 128
+ store volatile i64 %or, ptr %ptr
+ ret void
+}
diff --git a/llvm/test/CodeGen/SystemZ/xor-05.ll b/llvm/test/CodeGen/SystemZ/xor-05.ll
index 5640e236793e5..aec375368799a 100644
--- a/llvm/test/CodeGen/SystemZ/xor-05.ll
+++ b/llvm/test/CodeGen/SystemZ/xor-05.ll
@@ -2,7 +2,7 @@
;
; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
-; Check the lowest useful constant, expressed as a signed integer.
+; Check the lowest useful constant for i8, expressed as a signed integer.
define void @f1(ptr %ptr) {
; CHECK-LABEL: f1:
; CHECK: xi 0(%r2), 1
@@ -13,7 +13,49 @@ define void @f1(ptr %ptr) {
ret void
}
-; Check the highest useful constant, expressed as a signed integer.
+; Check lowest useful constant for i16, expressed as a signed integer.
+define void @f1_i16(ptr %ptr) {
+; CHECK-LABEL: f1_i16:
+; CHECK-NOT: xi 1(%r2)
+; CHECK: lh %r0, 0(%r2)
+; CHECK: xilf %r0, 65281
+; CHECK: sth %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, -255
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check lowest useful constant for i32, expressed as a signed integer.
+define void @f1_i32(ptr %ptr) {
+; CHECK-LABEL: f1_i32:
+; CHECK-NOT: xi 3(%r2)
+; CHECK: lhi %r0, -255
+; CHECK: x %r0, 0(%r2)
+; CHECK: st %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, -255
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check lowest useful constant for i64, expressed as a signed integer.
+define void @f1_i64(ptr %ptr) {
+; CHECK-LABEL: f1_i64:
+; CHECK-NOT: xi 7(%r2)
+; CHECK: lg {{%r[0-9]+}}, 0(%r2)
+; CHECK: xihf %r0, 4294967295
+; CHECK: stg {{%r[0-9]+}}, 0(%r2)
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, -255
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i8, expressed as a signed integer.
define void @f2(ptr %ptr) {
; CHECK-LABEL: f2:
; CHECK: xi 0(%r2), 254
@@ -24,7 +66,47 @@ define void @f2(ptr %ptr) {
ret void
}
-; Check the lowest useful constant, expressed as an unsigned integer.
+; Check the highest useful constant for i16, expressed as a signed integer.
+define void @f2_i16(ptr %ptr) {
+; CHECK-LABEL: f2_i16:
+; CHECK-NOT: xi 1(%r2), 254
+; CHECK: lh %r0, 0(%r2)
+; CHECK: xilf %r0, 65534
+; CHECK: sth %r0, 0(%r2)
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, -2
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i32, expressed as a signed integer.
+define void @f2_i32(ptr %ptr) {
+; CHECK-LABEL: f2_i32:
+; CHECK-NOT: xi 3(%r2)
+; CHECK: lhi %r0, -2
+; CHECK: x %r0, 0(%r2)
+; CHECK: st %r0, 0(%r2)
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, -2
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i64, expressed as a signed integer.
+define void @f2_i64(ptr %ptr) {
+; CHECK-LABEL: f2_i64:
+; CHECK-NOT: xi 7(%r2)
+; CHECK: lg [[REG:%r[0-9]+]], 0(%r2)
+; CHECK: xilf [[REG]], 4294967294
+; CHECK: stg [[REG]], 0(%r2)
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, -2
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the lowest useful constant for i8, expressed as an unsigned integer.
define void @f3(ptr %ptr) {
; CHECK-LABEL: f3:
; CHECK: xi 0(%r2), 1
@@ -35,7 +117,40 @@ define void @f3(ptr %ptr) {
ret void
}
-; Check the highest useful constant, expressed as a unsigned integer.
+; Check the lowest useful constant for i16, expressed as an unsigned integer.
+define void @f3_i16(ptr %ptr) {
+; CHECK-LABEL: f3_i16:
+; CHECK: xi 1(%r2), 1
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 1
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the lowest useful constant for i32, expressed as an unsigned integer.
+define void @f3_i32(ptr %ptr) {
+; CHECK-LABEL: f3_i32:
+; CHECK: xi 3(%r2), 1
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 1
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the lowest useful constant for i64, expressed as an unsigned integer.
+define void @f3_i64(ptr %ptr) {
+; CHECK-LABEL: f3_i64:
+; CHECK: xi 7(%r2), 1
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 1
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i8, expressed as a unsigned integer.
define void @f4(ptr %ptr) {
; CHECK-LABEL: f4:
; CHECK: xi 0(%r2), 254
@@ -46,7 +161,40 @@ define void @f4(ptr %ptr) {
ret void
}
-; Check the high end of the XI range.
+; Check the highest useful constant for i16, expressed as a unsigned integer.
+define void @f4_i16(ptr %ptr) {
+; CHECK-LABEL: f4_i16:
+; CHECK: xi 1(%r2), 254
+; CHECK: br %r14
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 254
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i32, expressed as a unsigned integer.
+define void @f4_i32(ptr %ptr) {
+; CHECK-LABEL: f4_i32:
+; CHECK: xi 3(%r2), 254
+; CHECK: br %r14
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 254
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the highest useful constant for i64, expressed as a unsigned integer.
+define void @f4_i64(ptr %ptr) {
+; CHECK-LABEL: f4_i64:
+; CHECK: xi 7(%r2), 254
+; CHECK: br %r14
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 254
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the high end of the XI range for i8.
define void @f5(ptr %src) {
; CHECK-LABEL: f5:
; CHECK: xi 4095(%r2), 127
@@ -58,7 +206,43 @@ define void @f5(ptr %src) {
ret void
}
-; Check the next byte up, which should use XIY instead of XI.
+; Check the high end of the XI range for i16.
+define void @f5_i16(ptr %src) {
+; CHECK-LABEL: f5_i16:
+; CHECK: xi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4094
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 127
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the high end of the XI range for i32.
+define void @f5_i32(ptr %src) {
+; CHECK-LABEL: f5_i32:
+; CHECK: xi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4092
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 127
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the high end of the XI range for i64.
+define void @f5_i64(ptr %src) {
+; CHECK-LABEL: f5_i64:
+; CHECK: xi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4088
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 127
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i8, which should use XIY instead of XI.
define void @f6(ptr %src) {
; CHECK-LABEL: f6:
; CHECK: xiy 4096(%r2), 127
@@ -70,7 +254,43 @@ define void @f6(ptr %src) {
ret void
}
-; Check the high end of the XIY range.
+; Check the next byte up for i16, which should use XIY instead of XI.
+define void @f6_i16(ptr %src) {
+; CHECK-LABEL: f6_i16:
+; CHECK: xiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4095
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 127
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i32, which should use XIY instead of XI.
+define void @f6_i32(ptr %src) {
+; CHECK-LABEL: f6_i32:
+; CHECK: xiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4093
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 127
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i64, which should use XIY instead of XI.
+define void @f6_i64(ptr %src) {
+; CHECK-LABEL: f6_i64:
+; CHECK: xiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4089
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 127
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the high end of the XIY range for i8.
define void @f7(ptr %src) {
; CHECK-LABEL: f7:
; CHECK: xiy 524287(%r2), 127
@@ -82,7 +302,43 @@ define void @f7(ptr %src) {
ret void
}
-; Check the next byte up, which needs separate address logic.
+; Check the high end of the XIY range for i16.
+define void @f7_i16(ptr %src) {
+; CHECK-LABEL: f7_i16:
+; CHECK: xiy 524287(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524286
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 127
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the high end of the XIY range for i32.
+define void @f7_i32(ptr %src) {
+; CHECK-LABEL: f7_i32:
+; CHECK: xiy 524287(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524284
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 127
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the high end of the XIY range for i64.
+define void @f7_i64(ptr %src) {
+; CHECK-LABEL: f7_i64:
+; CHECK: xiy 524287(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524280
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 127
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i8, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f8(ptr %src) {
; CHECK-LABEL: f8:
@@ -96,7 +352,49 @@ define void @f8(ptr %src) {
ret void
}
-; Check the high end of the negative XIY range.
+; Check the next byte up for i16, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f8_i16(ptr %src) {
+; CHECK-LABEL: f8_i16:
+; CHECK: agfi %r2, 524288
+; CHECK: xi 1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524288
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 127
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i32, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f8_i32(ptr %src) {
+; CHECK-LABEL: f8_i32:
+; CHECK: agfi %r2, 524288
+; CHECK: xi 3(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524288
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 127
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the next byte up for i64, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f8_i64(ptr %src) {
+; CHECK-LABEL: f8_i64:
+; CHECK: agfi %r2, 524288
+; CHECK: xi 7(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 524288
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 127
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the high end of the negative XIY range for i8.
define void @f9(ptr %src) {
; CHECK-LABEL: f9:
; CHECK: xiy -1(%r2), 127
@@ -108,7 +406,43 @@ define void @f9(ptr %src) {
ret void
}
-; Check the low end of the XIY range.
+; Check the high end of the negative XIY range for i16.
+define void @f9_i16(ptr %src) {
+; CHECK-LABEL: f9_i16:
+; CHECK: xiy -1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -2
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 127
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the high end of the negative XIY range for i32.
+define void @f9_i32(ptr %src) {
+; CHECK-LABEL: f9_i32:
+; CHECK: xiy -1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -4
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 127
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the high end of the negative XIY range for i64.
+define void @f9_i64(ptr %src) {
+; CHECK-LABEL: f9_i64:
+; CHECK: xiy -1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -8
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 127
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the low end of the XIY range for i8.
define void @f10(ptr %src) {
; CHECK-LABEL: f10:
; CHECK: xiy -524288(%r2), 127
@@ -120,7 +454,43 @@ define void @f10(ptr %src) {
ret void
}
-; Check the next byte down, which needs separate address logic.
+; Check the low end of the XIY range for i16.
+define void @f10_i16(ptr %src) {
+; CHECK-LABEL: f10_i16:
+; CHECK: xiy -524288(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524289
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 127
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the low end of the XIY range for i32.
+define void @f10_i32(ptr %src) {
+; CHECK-LABEL: f10_i32:
+; CHECK: xiy -524288(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524291
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 127
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the low end of the XIY range for i64.
+define void @f10_i64(ptr %src) {
+; CHECK-LABEL: f10_i64:
+; CHECK: xiy -524288(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524295
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 127
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check the next byte down for i8, which needs separate address logic.
; Other sequences besides this one would be OK.
define void @f11(ptr %src) {
; CHECK-LABEL: f11:
@@ -134,7 +504,49 @@ define void @f11(ptr %src) {
ret void
}
-; Check that XI does not allow an index
+; Check the next byte down for i16, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f11_i16(ptr %src) {
+; CHECK-LABEL: f11_i16:
+; CHECK: agfi %r2, -524290
+; CHECK: xi 1(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524290
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 127
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the next byte down for i32, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f11_i32(ptr %src) {
+; CHECK-LABEL: f11_i32:
+; CHECK: agfi %r2, -524292
+; CHECK: xi 3(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524292
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 127
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the next byte down for i64, which needs separate address logic.
+; Other sequences besides this one would be OK.
+define void @f11_i64(ptr %src) {
+; CHECK-LABEL: f11_i64:
+; CHECK: agfi %r2, -524296
+; CHECK: xi 7(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 -524296
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 127
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check that XI does not allow an index for i8.
define void @f12(i64 %src, i64 %index) {
; CHECK-LABEL: f12:
; CHECK: agr %r2, %r3
@@ -149,7 +561,52 @@ define void @f12(i64 %src, i64 %index) {
ret void
}
-; Check that XIY does not allow an index
+; Check the XI does not allow an index for i16.
+define void @f12_i16(i64 %src, i64 %index) {
+; CHECK-LABEL: f12_i16:
+; CHECK: agr %r2, %r3
+; CHECK: xi 4095(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4094
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 127
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the XI does not allow an index for i32.
+define void @f12_i32(i64 %src, i64 %index) {
+; CHECK-LABEL: f12_i32:
+; CHECK: agr %r2, %r3
+; CHECK: xi 4095(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4092
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 127
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the XI does not allow an index for i64.
+define void @f12_i64(i64 %src, i64 %index) {
+; CHECK-LABEL: f12_i64:
+; CHECK: agr %r2, %r3
+; CHECK: xi 4095(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4088
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 127
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check that XIY does not allow an index for i8.
define void @f13(i64 %src, i64 %index) {
; CHECK-LABEL: f13:
; CHECK: agr %r2, %r3
@@ -163,3 +620,144 @@ define void @f13(i64 %src, i64 %index) {
store i8 %xor, ptr %ptr
ret void
}
+
+; Check the XIY does not allow an index for i16.
+define void @f13_i16(i64 %src, i64 %index) {
+; CHECK-LABEL: f13_i16:
+; CHECK: agr %r2, %r3
+; CHECK: xiy 4096(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4095
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i16, ptr %ptr
+ %xor = xor i16 %val, 127
+ store i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check the XIY does not allow an index for i32.
+define void @f13_i32(i64 %src, i64 %index) {
+; CHECK-LABEL: f13_i32:
+; CHECK: agr %r2, %r3
+; CHECK: xiy 4096(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4093
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i32, ptr %ptr
+ %xor = xor i32 %val, 127
+ store i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check the XIY does not allow an index for i64.
+define void @f13_i64(i64 %src, i64 %index) {
+; CHECK-LABEL: f13_i64:
+; CHECK: agr %r2, %r3
+; CHECK: xiy 4096(%r2), 127
+; CHECK: br %r14
+ %add1 = add i64 %src, %index
+ %add2 = add i64 %add1, 4089
+ %ptr = inttoptr i64 %add2 to ptr
+ %val = load i64, ptr %ptr
+ %xor = xor i64 %val, 127
+ store i64 %xor, ptr %ptr
+ ret void
+}
+
+; Check XI with a i64 intermediate value for an i16.
+define void @f14_i16(ptr %src) {
+; CHECK-LABEL: f14_i16:
+; CHECK: xi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4094
+ %val = load i16, ptr %ptr
+ %ext = zext i16 %val to i64
+ %xor = xor i64 %ext, 127
+ %tr = trunc i64 %xor to i16
+ store i16 %tr, ptr %ptr
+ ret void
+}
+
+; Check XI with a i64 intermediate value for an i32.
+define void @f14_i32(ptr %src) {
+; CHECK-LABEL: f14_i32:
+; CHECK: xi 4095(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4092
+ %val = load i32, ptr %ptr
+ %ext = zext i32 %val to i64
+ %xor = xor i64 %ext, 127
+ %tr = trunc i64 %xor to i32
+ store i32 %tr, ptr %ptr
+ ret void
+}
+
+; Check XIY with a i64 intermediate value for an i16.
+define void @f15_i16(ptr %src) {
+; CHECK-LABEL: f15_i16:
+; CHECK: xiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4095
+ %val = load i16, ptr %ptr
+ %ext = zext i16 %val to i64
+ %xor = xor i64 %ext, 127
+ %tr = trunc i64 %xor to i16
+ store i16 %tr, ptr %ptr
+ ret void
+}
+
+; Check XIY with a i64 intermediate value for an i32.
+define void @f15_i32(ptr %src) {
+; CHECK-LABEL: f15_i32:
+; CHECK: xiy 4096(%r2), 127
+; CHECK: br %r14
+ %ptr = getelementptr i8, ptr %src, i64 4093
+ %val = load i32, ptr %ptr
+ %ext = zext i32 %val to i64
+ %xor = xor i64 %ext, 127
+ %tr = trunc i64 %xor to i32
+ store i32 %tr, ptr %ptr
+ ret void
+}
+
+; Check volatile i16 load/store with XOR is not folded.
+define void @f16_i16(ptr %ptr) {
+; CHECK-LABEL: f16_i16:
+; CHECK: lh [[REG:%r[0-5]]], 0(%r2)
+; CHECK-NEXT: xilf [[REG]], 128
+; CHECK-NOT: xi
+; CHECK-NOT: xiy
+; CHECK: br %r14
+ %val = load volatile i16, ptr %ptr
+ %xor = xor i16 %val, 128
+ store volatile i16 %xor, ptr %ptr
+ ret void
+}
+
+; Check volatile i32 load/store with XOR is not folded.
+define void @f16_i32(ptr %ptr) {
+; CHECK-LABEL: f16_i32:
+; CHECK: x [[REG:%r[0-5]]], 0(%r2)
+; CHECK-NOT: xi
+; CHECK-NOT: xiy
+; CHECK: br %r14
+ %val = load volatile i32, ptr %ptr
+ %xor = xor i32 %val, 128
+ store volatile i32 %xor, ptr %ptr
+ ret void
+}
+
+; Check volatile i64 load/store with XOR is not folded.
+define void @f16_i64(ptr %ptr) {
+; CHECK-LABEL: f16_i64:
+; CHECK: xg [[REG:%r[0-5]]], 0(%r2)
+; CHECK-NOT: xi
+; CHECK-NOT: xiy
+; CHECK: br %r14
+ %val = load volatile i64, ptr %ptr
+ %xor = xor i64 %val, 128
+ store volatile i64 %xor, ptr %ptr
+ ret void
+}
More information about the llvm-commits
mailing list