diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index ceb16174e13e7..ea73ed915bf03 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -1211,6 +1211,25 @@ class TargetInfo : public TransferrableTargetInfo, TiedOperand = N; // Don't copy Name or constraint string. } + + // For output operand constraints, the target can set bounds to indicate + // that the result value is guaranteed to fall within a certain range. + // This will cause corresponding assertions to be emitted that will allow + // for potential optimization based of that guarantee. + // + // NOTE: This re-uses the `ImmRange` fields to store the range, which are + // otherwise unused for constraint types used for output operands. + void setOutputOperandBounds(unsigned Min, unsigned Max) { + ImmRange.Min = Min; + ImmRange.Max = Max; + ImmRange.isConstrained = true; + } + std::optional> + getOutputOperandBounds() const { + return ImmRange.isConstrained + ? std::make_pair(ImmRange.Min, ImmRange.Max) + : std::optional>(); + } }; /// Validate register name used for global register variables. diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index 9e03a0846ffba..18641a96063cd 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1568,6 +1568,7 @@ bool AArch64TargetInfo::validateAsmConstraint( if (const unsigned Len = matchAsmCCConstraint(Name)) { Name += Len - 1; Info.setAllowsRegister(); + Info.setOutputOperandBounds(0, 2); return true; } } diff --git a/clang/lib/Basic/Targets/SystemZ.cpp b/clang/lib/Basic/Targets/SystemZ.cpp index 13b86234eed79..30f846cb900f8 100644 --- a/clang/lib/Basic/Targets/SystemZ.cpp +++ b/clang/lib/Basic/Targets/SystemZ.cpp @@ -99,6 +99,16 @@ bool SystemZTargetInfo::validateAsmConstraint( case 'T': // Likewise, plus an index Info.setAllowsMemory(); return true; + case '@': + // CC condition changes. + if (StringRef(Name) == "@cc") { + Name += 2; + Info.setAllowsRegister(); + // SystemZ has 2-bits CC, and hence Interval [0, 4). + Info.setOutputOperandBounds(0, 4); + return true; + } + return false; } } @@ -161,6 +171,9 @@ unsigned SystemZTargetInfo::getMinGlobalAlign(uint64_t Size, void SystemZTargetInfo::getTargetDefines(const LangOptions &Opts, MacroBuilder &Builder) const { + // Inline assembly supports SystemZ flag outputs. + Builder.defineMacro("__GCC_ASM_FLAG_OUTPUTS__"); + Builder.defineMacro("__s390__"); Builder.defineMacro("__s390x__"); Builder.defineMacro("__zarch__"); diff --git a/clang/lib/Basic/Targets/SystemZ.h b/clang/lib/Basic/Targets/SystemZ.h index dc2185e1b45ca..4e15d5af1cde6 100644 --- a/clang/lib/Basic/Targets/SystemZ.h +++ b/clang/lib/Basic/Targets/SystemZ.h @@ -136,6 +136,12 @@ class LLVM_LIBRARY_VISIBILITY SystemZTargetInfo : public TargetInfo { std::string convertConstraint(const char *&Constraint) const override { switch (Constraint[0]) { + case '@': // Flag output operand. + if (llvm::StringRef(Constraint) == "@cc") { + Constraint += 2; + return std::string("{@cc}"); + } + break; case 'p': // Keep 'p' constraint. return std::string("p"); case 'Z': diff --git a/clang/lib/Basic/Targets/X86.cpp b/clang/lib/Basic/Targets/X86.cpp index 6eb4db51d4e6e..187815c7969f6 100644 --- a/clang/lib/Basic/Targets/X86.cpp +++ b/clang/lib/Basic/Targets/X86.cpp @@ -1516,6 +1516,7 @@ bool X86TargetInfo::validateAsmConstraint( if (auto Len = matchAsmCCConstraint(Name)) { Name += Len - 1; Info.setAllowsRegister(); + Info.setOutputOperandBounds(0, 2); return true; } return false; diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 92636f27fd4e5..fdc1a11f6c55c 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -2674,7 +2674,8 @@ EmitAsmStores(CodeGenFunction &CGF, const AsmStmt &S, const llvm::ArrayRef ResultRegDests, const llvm::ArrayRef ResultRegQualTys, const llvm::BitVector &ResultTypeRequiresCast, - const llvm::BitVector &ResultRegIsFlagReg) { + const std::vector>> + &ResultBounds) { CGBuilderTy &Builder = CGF.Builder; CodeGenModule &CGM = CGF.CGM; llvm::LLVMContext &CTX = CGF.getLLVMContext(); @@ -2685,18 +2686,20 @@ EmitAsmStores(CodeGenFunction &CGF, const AsmStmt &S, // ResultRegDests can be also populated by addReturnRegisterOutputs() above, // in which case its size may grow. assert(ResultTypeRequiresCast.size() <= ResultRegDests.size()); - assert(ResultRegIsFlagReg.size() <= ResultRegDests.size()); + assert(ResultBounds.size() <= ResultRegDests.size()); for (unsigned i = 0, e = RegResults.size(); i != e; ++i) { llvm::Value *Tmp = RegResults[i]; llvm::Type *TruncTy = ResultTruncRegTypes[i]; - if ((i < ResultRegIsFlagReg.size()) && ResultRegIsFlagReg[i]) { - // Target must guarantee the Value `Tmp` here is lowered to a boolean - // value. - llvm::Constant *Two = llvm::ConstantInt::get(Tmp->getType(), 2); + if ((i < ResultBounds.size()) && ResultBounds[i].has_value()) { + const auto [LowerBound, UpperBound] = ResultBounds[i].value(); + // FIXME: Support for nonzero lower bounds not yet implemented. + assert(LowerBound == 0 && "Output operand lower bound is not zero."); + llvm::Constant *UpperBoundConst = + llvm::ConstantInt::get(Tmp->getType(), UpperBound); llvm::Value *IsBooleanValue = - Builder.CreateCmp(llvm::CmpInst::ICMP_ULT, Tmp, Two); + Builder.CreateCmp(llvm::CmpInst::ICMP_ULT, Tmp, UpperBoundConst); llvm::Function *FnAssume = CGM.getIntrinsic(llvm::Intrinsic::assume); Builder.CreateCall(FnAssume, IsBooleanValue); } @@ -2825,7 +2828,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { std::vector ArgElemTypes; std::vector Args; llvm::BitVector ResultTypeRequiresCast; - llvm::BitVector ResultRegIsFlagReg; + std::vector>> ResultBounds; // Keep track of inout constraints. std::string InOutConstraints; @@ -2883,8 +2886,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { ResultRegQualTys.push_back(QTy); ResultRegDests.push_back(Dest); - bool IsFlagReg = llvm::StringRef(OutputConstraint).starts_with("{@cc"); - ResultRegIsFlagReg.push_back(IsFlagReg); + ResultBounds.emplace_back(Info.getOutputOperandBounds()); llvm::Type *Ty = ConvertTypeForMem(QTy); const bool RequiresCast = Info.allowsRegister() && @@ -3231,7 +3233,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { EmitAsmStores(*this, S, RegResults, ResultRegTypes, ResultTruncRegTypes, ResultRegDests, ResultRegQualTys, ResultTypeRequiresCast, - ResultRegIsFlagReg); + ResultBounds); // If this is an asm goto with outputs, repeat EmitAsmStores, but with a // different insertion point; one for each indirect destination and with @@ -3242,7 +3244,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { Builder.SetInsertPoint(Succ, --(Succ->end())); EmitAsmStores(*this, S, CBRRegResults[Succ], ResultRegTypes, ResultTruncRegTypes, ResultRegDests, ResultRegQualTys, - ResultTypeRequiresCast, ResultRegIsFlagReg); + ResultTypeRequiresCast, ResultBounds); } } } diff --git a/clang/test/CodeGen/inline-asm-systemz-flag-output.c b/clang/test/CodeGen/inline-asm-systemz-flag-output.c new file mode 100644 index 0000000000000..041797b8b0639 --- /dev/null +++ b/clang/test/CodeGen/inline-asm-systemz-flag-output.c @@ -0,0 +1,57 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 6 +// RUN: %clang_cc1 -O2 -triple s390x-linux -emit-llvm -o - %s | FileCheck %s + +// CHECK-LABEL: define dso_local signext range(i32 0, 4) i32 @test( +// CHECK-SAME: i32 noundef signext [[X:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i32 } asm "ahi $0,42\0A", "=d,={@cc},0"(i32 [[X]]) #[[ATTR2:[0-9]+]], !srcloc [[META2:![0-9]+]] +// CHECK-NEXT: [[ASMRESULT1:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1 +// CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ASMRESULT1]], 4 +// CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP1]]) +// CHECK-NEXT: ret i32 [[ASMRESULT1]] +// +int test(int x) { + int cc; + asm ("ahi %[x],42\n" : [x] "+d"(x), "=@cc" (cc)); + return cc; +} + +// CHECK-LABEL: define dso_local signext range(i32 0, 2) i32 @test_low_high_transformation( +// CHECK-SAME: i32 noundef signext [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i32 } asm "ahi $0,42\0A", "=d,={@cc},0"(i32 [[X]]) #[[ATTR2]], !srcloc [[META3:![0-9]+]] +// CHECK-NEXT: [[ASMRESULT1:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1 +// CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ASMRESULT1]], 4 +// CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP1]]) +// CHECK-NEXT: [[TMP2:%.*]] = add nsw i32 [[ASMRESULT1]], -1 +// CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 2 +// CHECK-NEXT: [[LOR_EXT:%.*]] = zext i1 [[TMP3]] to i32 +// CHECK-NEXT: ret i32 [[LOR_EXT]] +// +int test_low_high_transformation(int x) { + int cc; + asm ("ahi %[x],42\n" : [x] "+d"(x), "=@cc" (cc)); + return cc == 1 || cc == 2; +} + +// CHECK-LABEL: define dso_local signext range(i32 0, 2) i32 @test_equal_high_transformation( +// CHECK-SAME: i32 noundef signext [[X:%.*]]) local_unnamed_addr #[[ATTR0]] { +// CHECK-NEXT: [[ENTRY:.*:]] +// CHECK-NEXT: [[TMP0:%.*]] = tail call { i32, i32 } asm "ahi $0,42\0A", "=d,={@cc},0"(i32 [[X]]) #[[ATTR2]], !srcloc [[META4:![0-9]+]] +// CHECK-NEXT: [[ASMRESULT1:%.*]] = extractvalue { i32, i32 } [[TMP0]], 1 +// CHECK-NEXT: [[TMP1:%.*]] = icmp ult i32 [[ASMRESULT1]], 4 +// CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP1]]) +// CHECK-NEXT: [[TMP2:%.*]] = and i32 [[ASMRESULT1]], 1 +// CHECK-NEXT: [[LOR_EXT:%.*]] = xor i32 [[TMP2]], 1 +// CHECK-NEXT: ret i32 [[LOR_EXT]] +// +int test_equal_high_transformation(int x) { + int cc; + asm ("ahi %[x],42\n" : [x] "+d"(x), "=@cc" (cc)); + return cc == 0 || cc == 2; +} +//. +// CHECK: [[META2]] = !{i64 788} +// CHECK: [[META3]] = !{i64 1670} +// CHECK: [[META4]] = !{i64 2505} +//. diff --git a/clang/test/Preprocessor/systemz_asm_flag_output.c b/clang/test/Preprocessor/systemz_asm_flag_output.c new file mode 100644 index 0000000000000..b627499d5ce46 --- /dev/null +++ b/clang/test/Preprocessor/systemz_asm_flag_output.c @@ -0,0 +1,4 @@ +// RUN: %clang -target systemz-unknown-unknown -x c -E -dM -o - %s | FileCheck -match-full-lines %s +// RUN: %clang -target s390x-unknown-unknown -x c -E -dM -o - %s | FileCheck -match-full-lines %s + +// CHECK: #define __GCC_ASM_FLAG_OUTPUTS__ 1 diff --git a/llvm/lib/Target/SystemZ/SystemZ.h b/llvm/lib/Target/SystemZ/SystemZ.h index a0cf881f365d5..5a06ea30054d6 100644 --- a/llvm/lib/Target/SystemZ/SystemZ.h +++ b/llvm/lib/Target/SystemZ/SystemZ.h @@ -24,6 +24,7 @@ class SystemZTargetMachine; namespace SystemZ { // Condition-code mask values. +const unsigned CCMASK_NONE = 0; const unsigned CCMASK_0 = 1 << 3; const unsigned CCMASK_1 = 1 << 2; const unsigned CCMASK_2 = 1 << 1; diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index 3b7d11a318dc4..de28faf4908e9 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -15,6 +15,7 @@ #include "SystemZConstantPoolValue.h" #include "SystemZMachineFunctionInfo.h" #include "SystemZTargetMachine.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -24,6 +25,7 @@ #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/IntrinsicsS390.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" @@ -1514,6 +1516,9 @@ SystemZTargetLowering::getConstraintType(StringRef Constraint) const { default: break; } + } else if (Constraint.size() == 5 && Constraint.starts_with("{")) { + if (StringRef("{@cc}").compare(Constraint) == 0) + return C_Other; } return TargetLowering::getConstraintType(Constraint); } @@ -1707,6 +1712,10 @@ SystemZTargetLowering::getRegForInlineAsmConstraint( return parseRegisterNumber(Constraint, &SystemZ::VR128BitRegClass, SystemZMC::VR128Regs, 32); } + if (Constraint[1] == '@') { + if (StringRef("{@cc}").compare(Constraint) == 0) + return std::make_pair(0u, &SystemZ::GR32BitRegClass); + } } return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT); } @@ -1737,6 +1746,38 @@ Register SystemZTargetLowering::getExceptionSelectorRegister( return Subtarget.isTargetXPLINK64() ? SystemZ::R2D : SystemZ::R7D; } +// Convert condition code in CCReg to an i32 value. +static SDValue getCCResult(SelectionDAG &DAG, SDValue CCReg) { + SDLoc DL(CCReg); + SDValue IPM = DAG.getNode(SystemZISD::IPM, DL, MVT::i32, CCReg); + return DAG.getNode(ISD::SRL, DL, MVT::i32, IPM, + DAG.getConstant(SystemZ::IPM_CC, DL, MVT::i32)); +} + +// Lower @cc targets via setcc. +SDValue SystemZTargetLowering::LowerAsmOutputForConstraint( + SDValue &Chain, SDValue &Glue, const SDLoc &DL, + const AsmOperandInfo &OpInfo, SelectionDAG &DAG) const { + if (StringRef("{@cc}").compare(OpInfo.ConstraintCode) != 0) + return SDValue(); + + // Check that return type is valid. + if (OpInfo.ConstraintVT.isVector() || !OpInfo.ConstraintVT.isInteger() || + OpInfo.ConstraintVT.getSizeInBits() < 8) + report_fatal_error("Glue output operand is of invalid type"); + + MachineFunction &MF = DAG.getMachineFunction(); + MachineRegisterInfo &MRI = MF.getRegInfo(); + MRI.addLiveIn(SystemZ::CC); + + if (Glue.getNode()) { + Glue = DAG.getCopyFromReg(Chain, DL, SystemZ::CC, MVT::i32, Glue); + Chain = Glue.getValue(1); + } else + Glue = DAG.getCopyFromReg(Chain, DL, SystemZ::CC, MVT::i32); + return getCCResult(DAG, Glue); +} + void SystemZTargetLowering::LowerAsmOperandForConstraint( SDValue Op, StringRef Constraint, std::vector &Ops, SelectionDAG &DAG) const { @@ -5300,14 +5341,6 @@ SDValue SystemZTargetLowering::lowerPREFETCH(SDValue Op, Node->getMemoryVT(), Node->getMemOperand()); } -// Convert condition code in CCReg to an i32 value. -static SDValue getCCResult(SelectionDAG &DAG, SDValue CCReg) { - SDLoc DL(CCReg); - SDValue IPM = DAG.getNode(SystemZISD::IPM, DL, MVT::i32, CCReg); - return DAG.getNode(ISD::SRL, DL, MVT::i32, IPM, - DAG.getConstant(SystemZ::IPM_CC, DL, MVT::i32)); -} - SDValue SystemZTargetLowering::lowerINTRINSIC_W_CHAIN(SDValue Op, SelectionDAG &DAG) const { @@ -8723,95 +8756,247 @@ SDValue SystemZTargetLowering::combineSETCC( return SDValue(); } -static bool combineCCMask(SDValue &CCReg, int &CCValid, int &CCMask) { +static std::pair findCCUse(const SDValue &Val) { + switch (Val.getOpcode()) { + default: + return std::make_pair(SDValue(), SystemZ::CCMASK_NONE); + case SystemZISD::IPM: + if (Val.getOperand(0).getOpcode() == SystemZISD::CLC || + Val.getOperand(0).getOpcode() == SystemZISD::STRCMP) + return std::make_pair(Val.getOperand(0), SystemZ::CCMASK_ICMP); + return std::make_pair(Val.getOperand(0), SystemZ::CCMASK_ANY); + case SystemZISD::SELECT_CCMASK: { + SDValue Op4CCReg = Val.getOperand(4); + if (Op4CCReg.getOpcode() == SystemZISD::ICMP || + Op4CCReg.getOpcode() == SystemZISD::TM) { + auto [OpCC, OpCCValid] = findCCUse(Op4CCReg.getOperand(0)); + if (OpCC != SDValue()) + return std::make_pair(OpCC, OpCCValid); + } + auto *CCValid = dyn_cast(Val.getOperand(2)); + if (!CCValid) + return std::make_pair(SDValue(), SystemZ::CCMASK_NONE); + int CCValidVal = CCValid->getZExtValue(); + return std::make_pair(Op4CCReg, CCValidVal); + } + case ISD::ADD: + case ISD::AND: + case ISD::OR: + case ISD::XOR: + case ISD::SHL: + case ISD::SRA: + case ISD::SRL: + auto [Op0CC, Op0CCValid] = findCCUse(Val.getOperand(0)); + if (Op0CC != SDValue()) + return std::make_pair(Op0CC, Op0CCValid); + return findCCUse(Val.getOperand(1)); + } +} + +static bool combineCCMask(SDValue &CCReg, int &CCValid, int &CCMask, + SelectionDAG &DAG); + +SmallVector static simplifyAssumingCCVal(SDValue &Val, SDValue &CC, + SelectionDAG &DAG) { + SDLoc DL(Val); + auto Opcode = Val.getOpcode(); + switch (Opcode) { + default: + return {}; + case ISD::Constant: + return {Val, Val, Val, Val}; + case SystemZISD::IPM: { + SDValue IPMOp0 = Val.getOperand(0); + if (IPMOp0 != CC) + return {}; + SmallVector ShiftedCCVals; + for (auto CC : {0, 1, 2, 3}) + ShiftedCCVals.emplace_back( + DAG.getConstant((CC << SystemZ::IPM_CC), DL, MVT::i32)); + return ShiftedCCVals; + } + case SystemZISD::SELECT_CCMASK: { + SDValue TrueVal = Val.getOperand(0), FalseVal = Val.getOperand(1); + auto *CCValid = dyn_cast(Val.getOperand(2)); + auto *CCMask = dyn_cast(Val.getOperand(3)); + if (!CCValid || !CCMask) + return {}; + + int CCValidVal = CCValid->getZExtValue(); + int CCMaskVal = CCMask->getZExtValue(); + const auto &&TrueSDVals = simplifyAssumingCCVal(TrueVal, CC, DAG); + const auto &&FalseSDVals = simplifyAssumingCCVal(FalseVal, CC, DAG); + if (TrueSDVals.empty() || FalseSDVals.empty()) + return {}; + SDValue Op4CCReg = Val.getOperand(4); + if (Op4CCReg != CC) + combineCCMask(Op4CCReg, CCValidVal, CCMaskVal, DAG); + if (Op4CCReg != CC) + return {}; + SmallVector MergedSDVals; + for (auto &CCVal : {0, 1, 2, 3}) + MergedSDVals.emplace_back(((CCMaskVal & (1 << (3 - CCVal))) != 0) + ? TrueSDVals[CCVal] + : FalseSDVals[CCVal]); + return MergedSDVals; + } + case ISD::ADD: + case ISD::AND: + case ISD::OR: + case ISD::XOR: + case ISD::SRA: + // Avoid introducing CC spills (because ADD/AND/OR/XOR/SRA + // would clobber CC). + if (!Val.hasOneUse()) + return {}; + [[fallthrough]]; + case ISD::SHL: + case ISD::SRL: + SDValue Op0 = Val.getOperand(0), Op1 = Val.getOperand(1); + const auto &&Op0SDVals = simplifyAssumingCCVal(Op0, CC, DAG); + const auto &&Op1SDVals = simplifyAssumingCCVal(Op1, CC, DAG); + if (Op0SDVals.empty() || Op1SDVals.empty()) + return {}; + SmallVector BinaryOpSDVals; + for (auto CCVal : {0, 1, 2, 3}) + BinaryOpSDVals.emplace_back(DAG.getNode( + Opcode, DL, Val.getValueType(), Op0SDVals[CCVal], Op1SDVals[CCVal])); + return BinaryOpSDVals; + } +} + +static bool combineCCMask(SDValue &CCReg, int &CCValid, int &CCMask, + SelectionDAG &DAG) { // We have a SELECT_CCMASK or BR_CCMASK comparing the condition code // set by the CCReg instruction using the CCValid / CCMask masks, - // If the CCReg instruction is itself a ICMP testing the condition + // If the CCReg instruction is itself a ICMP / TM testing the condition // code set by some other instruction, see whether we can directly // use that condition code. - - // Verify that we have an ICMP against some constant. - if (CCValid != SystemZ::CCMASK_ICMP) - return false; - auto *ICmp = CCReg.getNode(); - if (ICmp->getOpcode() != SystemZISD::ICMP) - return false; - auto *CompareLHS = ICmp->getOperand(0).getNode(); - auto *CompareRHS = dyn_cast(ICmp->getOperand(1)); - if (!CompareRHS) + auto *CCNode = CCReg.getNode(); + if (!CCNode) return false; - // Optimize the case where CompareLHS is a SELECT_CCMASK. - if (CompareLHS->getOpcode() == SystemZISD::SELECT_CCMASK) { - // Verify that we have an appropriate mask for a EQ or NE comparison. - bool Invert = false; - if (CCMask == SystemZ::CCMASK_CMP_NE) - Invert = !Invert; - else if (CCMask != SystemZ::CCMASK_CMP_EQ) + if (CCNode->getOpcode() == SystemZISD::TM) { + if (CCValid != SystemZ::CCMASK_TM) return false; - - // Verify that the ICMP compares against one of select values. - auto *TrueVal = dyn_cast(CompareLHS->getOperand(0)); - if (!TrueVal) - return false; - auto *FalseVal = dyn_cast(CompareLHS->getOperand(1)); - if (!FalseVal) + auto emulateTMCCMask = [](const SDValue &Op0Val, const SDValue &Op1Val) { + auto *Op0Node = dyn_cast(Op0Val.getNode()); + auto *Op1Node = dyn_cast(Op1Val.getNode()); + if (!Op0Node || !Op1Node) + return -1; + auto Op0APVal = Op0Node->getAPIntValue(); + auto Op1APVal = Op1Node->getAPIntValue(); + auto Result = Op0APVal & Op1APVal; + bool AllOnes = Result == Op1APVal; + bool AllZeros = Result == 0; + bool IsLeftMostBitSet = Result[Op1APVal.getActiveBits()] != 0; + return AllZeros ? 0 : AllOnes ? 3 : IsLeftMostBitSet ? 2 : 1; + }; + SDValue Op0 = CCNode->getOperand(0); + SDValue Op1 = CCNode->getOperand(1); + auto [Op0CC, Op0CCValid] = findCCUse(Op0); + if (Op0CC == SDValue()) return false; - if (CompareRHS->getAPIntValue() == FalseVal->getAPIntValue()) - Invert = !Invert; - else if (CompareRHS->getAPIntValue() != TrueVal->getAPIntValue()) + const auto &&Op0SDVals = simplifyAssumingCCVal(Op0, Op0CC, DAG); + const auto &&Op1SDVals = simplifyAssumingCCVal(Op1, Op0CC, DAG); + if (Op0SDVals.empty() || Op1SDVals.empty()) return false; - - // Compute the effective CC mask for the new branch or select. - auto *NewCCValid = dyn_cast(CompareLHS->getOperand(2)); - auto *NewCCMask = dyn_cast(CompareLHS->getOperand(3)); - if (!NewCCValid || !NewCCMask) - return false; - CCValid = NewCCValid->getZExtValue(); - CCMask = NewCCMask->getZExtValue(); - if (Invert) - CCMask ^= CCValid; - - // Return the updated CCReg link. - CCReg = CompareLHS->getOperand(4); + int NewCCMask = 0; + for (auto CC : {0, 1, 2, 3}) { + auto CCVal = emulateTMCCMask(Op0SDVals[CC], Op1SDVals[CC]); + if (CCVal < 0) + return false; + NewCCMask <<= 1; + NewCCMask |= (CCMask & (1 << (3 - CCVal))) != 0; + } + NewCCMask &= Op0CCValid; + CCReg = Op0CC; + CCMask = NewCCMask; + CCValid = Op0CCValid; return true; } + if (CCNode->getOpcode() != SystemZISD::ICMP || + CCValid != SystemZ::CCMASK_ICMP) + return false; - // Optimize the case where CompareRHS is (SRA (SHL (IPM))). - if (CompareLHS->getOpcode() == ISD::SRA) { - auto *SRACount = dyn_cast(CompareLHS->getOperand(1)); - if (!SRACount || SRACount->getZExtValue() != 30) - return false; - auto *SHL = CompareLHS->getOperand(0).getNode(); - if (SHL->getOpcode() != ISD::SHL) - return false; - auto *SHLCount = dyn_cast(SHL->getOperand(1)); - if (!SHLCount || SHLCount->getZExtValue() != 30 - SystemZ::IPM_CC) - return false; - auto *IPM = SHL->getOperand(0).getNode(); - if (IPM->getOpcode() != SystemZISD::IPM) - return false; - - // Avoid introducing CC spills (because SRA would clobber CC). - if (!CompareLHS->hasOneUse()) - return false; - // Verify that the ICMP compares against zero. - if (CompareRHS->getZExtValue() != 0) + SDValue CmpOp0 = CCNode->getOperand(0); + SDValue CmpOp1 = CCNode->getOperand(1); + SDValue CmpOp2 = CCNode->getOperand(2); + auto [Op0CC, Op0CCValid] = findCCUse(CmpOp0); + if (Op0CC != SDValue()) { + const auto &&Op0SDVals = simplifyAssumingCCVal(CmpOp0, Op0CC, DAG); + const auto &&Op1SDVals = simplifyAssumingCCVal(CmpOp1, Op0CC, DAG); + if (Op0SDVals.empty() || Op1SDVals.empty()) return false; - // Compute the effective CC mask for the new branch or select. - CCMask = SystemZ::reverseCCMask(CCMask); - - // Return the updated CCReg link. - CCReg = IPM->getOperand(0); + auto *CmpType = dyn_cast(CmpOp2); + auto CmpTypeVal = CmpType->getZExtValue(); + const auto compareCCSigned = [&CmpTypeVal](const SDValue &Op0Val, + const SDValue &Op1Val) { + auto *Op0Node = dyn_cast(Op0Val.getNode()); + auto *Op1Node = dyn_cast(Op1Val.getNode()); + if (!Op0Node || !Op1Node) + return -1; + auto Op0APVal = Op0Node->getAPIntValue(); + auto Op1APVal = Op1Node->getAPIntValue(); + if (CmpTypeVal == SystemZICMP::SignedOnly) + return Op0APVal == Op1APVal ? 0 : Op0APVal.slt(Op1APVal) ? 1 : 2; + return Op0APVal == Op1APVal ? 0 : Op0APVal.ult(Op1APVal) ? 1 : 2; + }; + int NewCCMask = 0; + for (auto CC : {0, 1, 2, 3}) { + auto CCVal = compareCCSigned(Op0SDVals[CC], Op1SDVals[CC]); + if (CCVal < 0) + return false; + NewCCMask <<= 1; + NewCCMask |= (CCMask & (1 << (3 - CCVal))) != 0; + } + NewCCMask &= Op0CCValid; + CCMask = NewCCMask; + CCReg = Op0CC; + CCValid = Op0CCValid; return true; } return false; } -SDValue SystemZTargetLowering::combineBR_CCMASK( - SDNode *N, DAGCombinerInfo &DCI) const { +// Merging versus split in multiple branches cost. +TargetLoweringBase::CondMergingParams +SystemZTargetLowering::getJumpConditionMergingParams(Instruction::BinaryOps Opc, + const Value *Lhs, + const Value *Rhs) const { + const auto isFlagOutOpCC = [](const Value *V) { + using namespace llvm::PatternMatch; + const Value *RHSVal; + const APInt *RHSC; + if (const auto *I = dyn_cast(V)) { + // PatternMatch.h provides concise tree-based pattern match of llvm IR. + if (match(I->getOperand(0), m_And(m_Value(RHSVal), m_APInt(RHSC))) || + match(I, m_Cmp(m_Value(RHSVal), m_APInt(RHSC)))) { + if (const auto *CB = dyn_cast(RHSVal)) { + if (CB->isInlineAsm()) { + const InlineAsm *IA = cast(CB->getCalledOperand()); + return IA && + IA->getConstraintString().find("{@cc}") != std::string::npos; + } + } + } + } + return false; + }; + // Pattern (ICmp %asm) or (ICmp (And %asm)). + // Cost of longest dependency chain (ICmp, And) is 2. CostThreshold or + // BaseCost can be set >=2. If cost of instruction <= CostThreshold + // conditionals will be merged or else conditionals will be split. + if (isFlagOutOpCC(Lhs) && isFlagOutOpCC(Rhs)) + return {3, 0, -1}; + // Default. + return {-1, -1, -1}; +} + +SDValue SystemZTargetLowering::combineBR_CCMASK(SDNode *N, + DAGCombinerInfo &DCI) const { SelectionDAG &DAG = DCI.DAG; // Combine BR_CCMASK (ICMP (SELECT_CCMASK)) into a single BR_CCMASK. @@ -8824,8 +9009,7 @@ SDValue SystemZTargetLowering::combineBR_CCMASK( int CCMaskVal = CCMask->getZExtValue(); SDValue Chain = N->getOperand(0); SDValue CCReg = N->getOperand(4); - - if (combineCCMask(CCReg, CCValidVal, CCMaskVal)) + if (combineCCMask(CCReg, CCValidVal, CCMaskVal, DAG)) return DAG.getNode(SystemZISD::BR_CCMASK, SDLoc(N), N->getValueType(0), Chain, DAG.getTargetConstant(CCValidVal, SDLoc(N), MVT::i32), @@ -8848,16 +9032,80 @@ SDValue SystemZTargetLowering::combineSELECT_CCMASK( int CCMaskVal = CCMask->getZExtValue(); SDValue CCReg = N->getOperand(4); - if (combineCCMask(CCReg, CCValidVal, CCMaskVal)) - return DAG.getNode(SystemZISD::SELECT_CCMASK, SDLoc(N), N->getValueType(0), - N->getOperand(0), N->getOperand(1), - DAG.getTargetConstant(CCValidVal, SDLoc(N), MVT::i32), - DAG.getTargetConstant(CCMaskVal, SDLoc(N), MVT::i32), - CCReg); + bool IsCombinedCCReg = combineCCMask(CCReg, CCValidVal, CCMaskVal, DAG); + + // Populate SDVals vector for each condition code ccval for given Val, which + // can again be another nested select_ccmask with the same CC. + const auto constructCCSDValsFromSELECT = [&CCReg](SDValue &Val) { + if (Val.getOpcode() == SystemZISD::SELECT_CCMASK) { + SmallVector Res; + if (Val.getOperand(4) != CCReg) + return SmallVector{}; + SDValue TrueVal = Val.getOperand(0), FalseVal = Val.getOperand(1); + auto *CCMask = dyn_cast(Val.getOperand(3)); + if (!CCMask) + return SmallVector{}; + + int CCMaskVal = CCMask->getZExtValue(); + for (auto &CC : {0, 1, 2, 3}) + Res.emplace_back(((CCMaskVal & (1 << (3 - CC))) != 0) ? TrueVal + : FalseVal); + return Res; + } + return SmallVector{Val, Val, Val, Val}; + }; + // Attempting to optimize TrueVal/FalseVal in outermost select_ccmask either + // with CCReg found by combineCCMask or original CCReg. + SDValue TrueVal = N->getOperand(0); + SDValue FalseVal = N->getOperand(1); + auto &&TrueSDVals = simplifyAssumingCCVal(TrueVal, CCReg, DAG); + auto &&FalseSDVals = simplifyAssumingCCVal(FalseVal, CCReg, DAG); + // TrueSDVals/FalseSDVals might be empty in case of non-constant + // TrueVal/FalseVal for select_ccmask, which can not be optimized further. + if (TrueSDVals.empty()) + TrueSDVals = constructCCSDValsFromSELECT(TrueVal); + if (FalseSDVals.empty()) + FalseSDVals = constructCCSDValsFromSELECT(FalseVal); + if (!TrueSDVals.empty() && !FalseSDVals.empty()) { + SmallSet MergedSDValsSet; + // Ignoring CC values outside CCValiid. + for (auto CC : {0, 1, 2, 3}) { + if ((CCValidVal & ((1 << (3 - CC)))) != 0) + MergedSDValsSet.insert(((CCMaskVal & (1 << (3 - CC))) != 0) + ? TrueSDVals[CC] + : FalseSDVals[CC]); + } + if (MergedSDValsSet.size() == 1) + return *MergedSDValsSet.begin(); + if (MergedSDValsSet.size() == 2) { + auto BeginIt = MergedSDValsSet.begin(); + SDValue NewTrueVal = *BeginIt, NewFalseVal = *next(BeginIt); + if (NewTrueVal == FalseVal || NewFalseVal == TrueVal) + std::swap(NewTrueVal, NewFalseVal); + int NewCCMask = 0; + for (auto CC : {0, 1, 2, 3}) { + NewCCMask <<= 1; + NewCCMask |= ((CCMaskVal & (1 << (3 - CC))) != 0) + ? (TrueSDVals[CC] == NewTrueVal) + : (FalseSDVals[CC] == NewTrueVal); + } + CCMaskVal = NewCCMask; + CCMaskVal &= CCValidVal; + TrueVal = NewTrueVal; + FalseVal = NewFalseVal; + IsCombinedCCReg = true; + } + } + + if (IsCombinedCCReg) + return DAG.getNode( + SystemZISD::SELECT_CCMASK, SDLoc(N), N->getValueType(0), TrueVal, + FalseVal, DAG.getTargetConstant(CCValidVal, SDLoc(N), MVT::i32), + DAG.getTargetConstant(CCMaskVal, SDLoc(N), MVT::i32), CCReg); + return SDValue(); } - SDValue SystemZTargetLowering::combineGET_CCMASK( SDNode *N, DAGCombinerInfo &DCI) const { diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.h b/llvm/lib/Target/SystemZ/SystemZISelLowering.h index f8706b748b355..d5b76031766dd 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -533,6 +533,18 @@ class SystemZTargetLowering : public TargetLowering { } const char *getTargetNodeName(unsigned Opcode) const override; + + // This function currently returns cost for srl/ipm/cc sequence for merging. + CondMergingParams + getJumpConditionMergingParams(Instruction::BinaryOps Opc, const Value *Lhs, + const Value *Rhs) const override; + + // Handle Lowering flag assembly outputs. + SDValue LowerAsmOutputForConstraint(SDValue &Chain, SDValue &Flag, + const SDLoc &DL, + const AsmOperandInfo &Constraint, + SelectionDAG &DAG) const override; + std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override; diff --git a/llvm/test/CodeGen/SystemZ/htm-intrinsics.ll b/llvm/test/CodeGen/SystemZ/htm-intrinsics.ll index c6ee8042a5f2a..07fbed9bd0dd7 100644 --- a/llvm/test/CodeGen/SystemZ/htm-intrinsics.ll +++ b/llvm/test/CodeGen/SystemZ/htm-intrinsics.ll @@ -90,7 +90,7 @@ define i32 @test_tbegin_nofloat4(i32 %pad, ptr %ptr) { ; CHECK: tbegin 0, 65292 ; CHECK: ipm %r2 ; CHECK: srl %r2, 28 -; CHECK: ciblh %r2, 2, 0(%r14) +; CHECK: bnhr %r14 ; CHECK: mvhi 0(%r3), 0 ; CHECK: br %r14 %res = call i32 @llvm.s390.tbegin.nofloat(ptr null, i32 65292) @@ -219,7 +219,7 @@ define i32 @test_tend2(i32 %pad, ptr %ptr) { ; CHECK: tend ; CHECK: ipm %r2 ; CHECK: srl %r2, 28 -; CHECK: ciblh %r2, 2, 0(%r14) +; CHECK: bnhr %r14 ; CHECK: mvhi 0(%r3), 0 ; CHECK: br %r14 %res = call i32 @llvm.s390.tend() diff --git a/llvm/test/CodeGen/SystemZ/inline-asm-flag-output-01.ll b/llvm/test/CodeGen/SystemZ/inline-asm-flag-output-01.ll new file mode 100644 index 0000000000000..6b8746e05704c --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/inline-asm-flag-output-01.ll @@ -0,0 +1,738 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc < %s -verify-machineinstrs -mtriple=s390x-linux-gnu -O2 | FileCheck %s +; Test implementation of combining br_ccmask for flag output operand, and +; optimizing ipm sequence using conditional branches. + +declare void @dummy() + +; Check a case where the cc is used as an integer. +; Just (srl (ipm)) sequence without optimization. +define i32 @test(ptr %a) { +; CHECK-LABEL: test: +; CHECK: # %bb.0: +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ipm %r2 +; CHECK-NEXT: srl %r2, 28 +; CHECK-NEXT: br %r14 + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + ret i32 %cc +} + +; Test-1(f1_0_*). Test all 14 valid combinations, where cc is being used for +; branching. + +; Check (cc == 0). +define void @f1_0_eq_0(ptr %a) { +; CHECK-LABEL: f1_0_eq_0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jge dummy@PLT +; CHECK-NEXT: .LBB1_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp eq i32 %cc, 0 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc != 0). +define void @f1_0_ne_0(ptr %a) { +; CHECK-LABEL: f1_0_ne_0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgne dummy@PLT +; CHECK-NEXT: .LBB2_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp ugt i32 %cc, 0 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc == 1). +define void @f1_0_eq_1(ptr %a) { +; CHECK-LABEL: f1_0_eq_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgl dummy@PLT +; CHECK-NEXT: .LBB3_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp eq i32 %cc, 1 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc != 1). +define void @f1_0_ne_1(ptr %a) { +; CHECK-LABEL: f1_0_ne_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnl dummy@PLT +; CHECK-NEXT: .LBB4_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp ne i32 %cc, 1 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc == 2). +define void @f1_0_eq_2(ptr %a) { +; CHECK-LABEL: f1_0_eq_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgh dummy@PLT +; CHECK-NEXT: .LBB5_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp eq i32 %cc, 2 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc != 2). +define void @f1_0_ne_2(ptr %a) { +; CHECK-LABEL: f1_0_ne_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnh dummy@PLT +; CHECK-NEXT: .LBB6_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp ne i32 %cc, 2 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc == 3). +define void @f1_0_eq_3(ptr %a) { +; CHECK-LABEL: f1_0_eq_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgo dummy@PLT +; CHECK-NEXT: .LBB7_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp eq i32 %cc, 3 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc != 3). +define void @f1_0_ne_3(ptr %a) { +; CHECK-LABEL: f1_0_ne_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgno dummy@PLT +; CHECK-NEXT: .LBB8_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp ult i32 %cc, 3 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc == 0|1). +define void @f1_0_01(ptr %a) { +; CHECK-LABEL: f1_0_01: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgle dummy@PLT +; CHECK-NEXT: .LBB9_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp ult i32 %cc, 2 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc == 0|2). +define void @f1_0_02(ptr %a) { +; CHECK-LABEL: f1_0_02: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jghe dummy@PLT +; CHECK-NEXT: .LBB10_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cmp = icmp eq i32 %and, 0 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc == 0|3). +define void @f1_0_03(ptr %a) { +; CHECK-LABEL: f1_0_03: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnlh dummy@PLT +; CHECK-NEXT: .LBB11_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp0 = icmp ne i32 %cc, 0 + %cmp3 = icmp ne i32 %cc, 3 + %cmp.inv = and i1 %cmp0, %cmp3 + br i1 %cmp.inv, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc == 1|2). +define void @f1_0_12(ptr %a) { +; CHECK-LABEL: f1_0_12: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jglh dummy@PLT +; CHECK-NEXT: .LBB12_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmpeq1 = icmp eq i32 %cc, 1 + %cmpeq2 = icmp eq i32 %cc, 2 + %cmp = or i1 %cmpeq1, %cmpeq2 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc == 1|3). +define void @f1_0_13(ptr %a) { +; CHECK-LABEL: f1_0_13: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnhe dummy@PLT +; CHECK-NEXT: .LBB13_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmpeq1 = icmp eq i32 %cc, 1 + %cmpeq3 = icmp eq i32 %cc, 3 + %cmp = or i1 %cmpeq1, %cmpeq3 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check (cc == 2|3). +define void @f1_0_23(ptr %a) { +; CHECK-LABEL: f1_0_23: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnle dummy@PLT +; CHECK-NEXT: .LBB14_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmp = icmp ugt i32 %cc, 1 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Test-2(f1_1_*/f1_2_*/fl_3_*/f1_4_*). +; Test Mixed patterns involving Binary Ops. + +; Check 'add' for (cc != 0). +define void @f1_1_1(ptr %a) { +; CHECK-LABEL: f1_1_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgne dummy@PLT +; CHECK-NEXT: .LBB15_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cmp = icmp ult i32 %add, 3 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'add' for (cc == 1|2). +define void @f1_1_2(ptr %a) { +; CHECK-LABEL: f1_1_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jglh dummy@PLT +; CHECK-NEXT: .LBB16_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cmp = icmp ult i32 %add, 2 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'add' for (cc == 1|2). +define void @f1_1_3(ptr %a) { +; CHECK-LABEL: f1_1_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jglh dummy@PLT +; CHECK-NEXT: .LBB17_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -3 + %cmp.inv = icmp ult i32 %add, -2 + br i1 %cmp.inv, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'and' with one operand cc and other select_ccmask(cc !=1). +define void @f1_2_1(ptr %a) { +; CHECK-LABEL: f1_2_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnl dummy@PLT +; CHECK-NEXT: .LBB18_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpne0 = icmp ne i32 %andcc, 0 + %cmpne3 = icmp ne i32 %cc, 3 + %cmp.inv = and i1 %cmpne3, %cmpne0 + br i1 %cmp.inv, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'and' with both operands select_ccmask(cc != 2). +define void @f1_2_2(ptr %a) { +; CHECK-LABEL: f1_2_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnh dummy@PLT +; CHECK-NEXT: .LBB19_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %ugt1 = icmp samesign ugt i32 %cc, 1 + %cmpne3 = icmp ne i32 %cc, 3 + %and.cond.inv = and i1 %ugt1, %cmpne3 + br i1 %and.cond.inv, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'and/tm' for (cc == 0|2). +define void @f1_2_3(ptr %a) { +; CHECK-LABEL: f1_2_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jghe dummy@PLT +; CHECK-NEXT: .LBB20_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cmp = icmp eq i32 %and, 0 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'and/tm' for (cc == 1|3). +define void @f1_2_4(ptr %a) { +; CHECK-LABEL: f1_2_4: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnhe dummy@PLT +; CHECK-NEXT: .LBB21_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cmp = icmp eq i32 %and, 0 + br i1 %cmp, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'icmp' with one operand 'and' and other 'select_ccmask'(cc != 1). +define void @f1_2_5(ptr %a) { +; CHECK-LABEL: f1_2_5: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnl dummy@PLT +; CHECK-NEXT: .LBB22_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne3 = icmp ne i32 %cc, 3 + %cmp = xor i1 %cmpne3, %trunc + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check nested 'xor' cc with select_ccmask(cc != 1). +define void @f1_3_1(ptr %a) { +; CHECK-LABEL: f1_3_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnl dummy@PLT +; CHECK-NEXT: .LBB23_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmpeq0 = icmp eq i32 %cc, 0 + %cmpeq2 = icmp eq i32 %cc, 2 + %xor = xor i1 %cmpeq0, %cmpeq2 + %cmpne3 = icmp ne i32 %cc, 3 + %cmp.inv = xor i1 %cmpne3, %xor + br i1 %cmp.inv, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=1). +define void @f1_3_2(ptr %a) { +; CHECK-LABEL: f1_3_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnl dummy@PLT +; CHECK-NEXT: .LBB24_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpeq3 = icmp eq i32 %cc, 3 + %cmp.inv = xor i1 %cmpeq3, %trunc + br i1 %cmp.inv, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=2). +define void @f1_3_3(ptr %a) { +; CHECK-LABEL: f1_3_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgnh dummy@PLT +; CHECK-NEXT: .LBB25_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne0 = icmp ne i32 %cc, 0 + %cmp.cond.inv = xor i1 %cmpne0, %trunc + br i1 %cmp.cond.inv, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'or' with both operands are select_ccmask one with TM and other with +; ICMP(cc == 1). +define void @f1_4_1(ptr %a) { +; CHECK-LABEL: f1_4_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgl dummy@PLT +; CHECK-NEXT: .LBB26_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpeq0 = icmp eq i32 %andcc, 0 + %cmpeq3 = icmp eq i32 %cc, 3 + %cmp.cond.inv = or i1 %cmpeq3, %cmpeq0 + br i1 %cmp.cond.inv, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'or' for (cc == 0|1). +define void @f1_4_2(ptr %a) { +; CHECK-LABEL: f1_4_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgle dummy@PLT +; CHECK-NEXT: .LBB27_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cmp.inv = icmp samesign ugt i32 %or, -3 + br i1 %cmp.inv, label %exit, label %branch +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + +; Check 'or' for (cc == 0|1). +define void @f1_4_3(ptr %a) { +; CHECK-LABEL: f1_4_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jgle dummy@PLT +; CHECK-NEXT: .LBB28_1: # %exit +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cmp = icmp samesign ult i32 %or, -2 + br i1 %cmp, label %branch, label %exit +branch: + tail call void @dummy() + br label %exit +exit: + ret void +} + diff --git a/llvm/test/CodeGen/SystemZ/inline-asm-flag-output-02.ll b/llvm/test/CodeGen/SystemZ/inline-asm-flag-output-02.ll new file mode 100644 index 0000000000000..b9b9a4b779b8a --- /dev/null +++ b/llvm/test/CodeGen/SystemZ/inline-asm-flag-output-02.ll @@ -0,0 +1,1665 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5 +; RUN: llc < %s -verify-machineinstrs -mtriple=s390x-linux-gnu -O2 | FileCheck %s +; Test implementation of combining select_ccmask for flag output operand and +; optimizing ipm sequence using conditional branches. + +; Test-1(f2_0_*): Both TrueVal and FalseVal non-const(14-valid CCMask). + +; Check (cc == 0). +define i64 @f2_0_eq_0(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_eq_0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: ber %r14 +; CHECK-NEXT: .LBB0_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp eq i32 %cc, 0 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc != 0). +define i64 @f2_0_ne_0(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_ne_0: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bner %r14 +; CHECK-NEXT: .LBB1_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp ugt i32 %cc, 0 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc == 1). +define i64 @f2_0_eq_1(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_eq_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB2_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp eq i32 %cc, 1 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc != 1). +define i64 @f2_0_ne_1(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_ne_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnlr %r14 +; CHECK-NEXT: .LBB3_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp ne i32 %cc, 1 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc == 2). +define i64 @f2_0_eq_2(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_eq_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bhr %r14 +; CHECK-NEXT: .LBB4_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp eq i32 %cc, 2 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc != 2). +define i64 @f2_0_ne_2(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_ne_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnhr %r14 +; CHECK-NEXT: .LBB5_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp ne i32 %cc, 2 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc == 3). +define i64 @f2_0_eq_3(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_eq_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bor %r14 +; CHECK-NEXT: .LBB6_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp eq i32 %cc, 3 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc != 3). +define i64 @f2_0_ne_3(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_ne_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnor %r14 +; CHECK-NEXT: .LBB7_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp ult i32 %cc, 3 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc == 0|1). +define i64 @f2_0_01(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_01: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bler %r14 +; CHECK-NEXT: .LBB8_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp ult i32 %cc, 2 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc == 0|2). +define i64 @f2_0_02(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_02: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB9_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %and = and i32 %cc, 1 + %cond = icmp eq i32 %and, 0 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check (cc == 0|3). +define i64 @f2_0_03(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_0_03: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blhr %r14 +; CHECK-NEXT: .LBB10_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cmp0 = icmp ne i32 %cc, 0 + %cmp3 = icmp ne i32 %cc, 3 + %cond.inv = and i1 %cmp0, %cmp3 + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check (cc == 1|2). +define i64 @f2_0_12(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_0_12: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnlhr %r14 +; CHECK-NEXT: .LBB11_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %add = add nsw i32 %cc, -3 + %cond.inv = icmp ult i32 %add, -2 + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check (cc == 1|3). +define i64 @f2_0_13(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_0_13: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB12_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %and = and i32 %cc, 1 + %cond.inv = icmp eq i32 %and, 0 + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check (cc == 2|3). +define i64 @f2_0_23(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_0_23: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnler %r14 +; CHECK-NEXT: .LBB13_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %cond = icmp ugt i32 %cc, 1 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Test-2(f2_1_*/f2_2_*/f2_3_*/f2_4_*). +; Both TrueVal and FalseVal are non-const with mixed patterns involving +; Binary Ops. + +; Check 'add' for (cc != 0). +define i64 @f2_1_1(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_1_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bner %r14 +; CHECK-NEXT: .LBB14_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cond = icmp ult i32 %add, 3 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check 'add' for (cc == 1|2). +define i64 @f2_1_2(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_1_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blhr %r14 +; CHECK-NEXT: .LBB15_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cond = icmp ult i32 %add, 2 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check 'add' for (cc == 1|2). +define i64 @f2_1_3(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_1_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnlhr %r14 +; CHECK-NEXT: .LBB16_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -3 + %cond.inv = icmp ult i32 %add, -2 + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check 'and' with one operand cc and other select_ccmask(cc !=1). +define i64 @f2_2_1(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_2_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB17_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpne0 = icmp ne i32 %andcc, 0 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = and i1 %cmpne3, %cmpne0 + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check 'and' with both operands select_ccmask(cc != 2). +define i64 @f2_2_2(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_2_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bhr %r14 +; CHECK-NEXT: .LBB18_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %ugt1 = icmp samesign ugt i32 %cc, 1 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = and i1 %ugt1, %cmpne3 + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check 'and/tm' for (cc == 0|2). +define i64 @f2_2_3(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_2_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB19_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cond = icmp eq i32 %and, 0 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Check 'and/tm' for (cc == 1|3). +define i64 @f2_2_4(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_2_4: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB20_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cond.inv = icmp eq i32 %and, 0 + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check 'icmp' with one operand 'and' and other 'select_ccmask'(cc != 1). +define i64 @f2_2_5(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_2_5: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnlr %r14 +; CHECK-NEXT: .LBB21_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne3 = icmp ne i32 %cc, 3 + %cond = xor i1 %cmpne3, %trunc + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + + +; Check nested 'xor' cc with select_ccmask(cc != 1). +define i64 @f2_3_1(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_3_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB22_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmpeq0 = icmp eq i32 %cc, 0 + %cmpeq2 = icmp eq i32 %cc, 2 + %xor = xor i1 %cmpeq0, %cmpeq2 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = xor i1 %cmpne3, %xor + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=1). +define i64 @f2_3_2(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_3_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB23_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpeq3 = icmp eq i32 %cc, 3 + %cond.inv = xor i1 %cmpeq3, %trunc + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=2). +define i64 @f2_3_3(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_3_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bhr %r14 +; CHECK-NEXT: .LBB24_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne0 = icmp ne i32 %cc, 0 + %cond.inv = xor i1 %cmpne0, %trunc + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check 'or' with both operands select_ccmask with TM and ICMP(cc == 1). +define i64 @f2_4_1(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_4_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnlr %r14 +; CHECK-NEXT: .LBB25_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpeq0 = icmp eq i32 %andcc, 0 + %cmpeq3 = icmp eq i32 %cc, 3 + %cond.inv = or i1 %cmpeq3, %cmpeq0 + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check 'or' for (cc == 0|1). +define i64 @f2_4_2(i64 %y, i64 %x, ptr %a) { +; CHECK-LABEL: f2_4_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnler %r14 +; CHECK-NEXT: .LBB26_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cond.inv = icmp samesign ugt i32 %or, -3 + %res = select i1 %cond.inv, i64 %y, i64 %x + ret i64 %res +} + +; Check 'or' for (cc == 0|1). +define i64 @f2_4_3(i64 %x, i64 %y, ptr %a) { +; CHECK-LABEL: f2_4_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r4), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bler %r14 +; CHECK-NEXT: .LBB27_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cond = icmp samesign ult i32 %or, -2 + %res = select i1 %cond, i64 %x, i64 %y + ret i64 %res +} + +; Test-3(f3_1_*/f3_2_*/f3_3_*/f3_4_*). +; TrueVal is non-const and FalseVal is const with mixed patterns involving +; Binary Ops. + +; Check 'add' for (cc != 0). +define i64 @f3_1_1(i64 %x, ptr %a) { +; CHECK-LABEL: f3_1_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bner %r14 +; CHECK-NEXT: .LBB28_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cond = icmp ult i32 %add, 3 + %res = select i1 %cond, i64 %x, i64 5 + ret i64 %res +} + +; Check 'add' for (cc == 1|2). +define i64 @f3_1_2(i64 %x, ptr %a) { +; CHECK-LABEL: f3_1_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blhr %r14 +; CHECK-NEXT: .LBB29_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cond = icmp ult i32 %add, 2 + %res = select i1 %cond, i64 %x, i64 5 + ret i64 %res +} + +; Check 'add' for (cc == 1|2). +define i64 @f3_1_3(ptr %a, i64 %x) { +; CHECK-LABEL: f3_1_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bnlhr %r14 +; CHECK-NEXT: .LBB30_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -3 + %cond.inv = icmp ult i32 %add, -2 + %res = select i1 %cond.inv, i64 5, i64 %x + ret i64 %res +} + +; Check 'and' with one operand cc and other select_ccmask(cc !=1). +define i64 @f3_2_1(ptr %a, i64 %x) { +; CHECK-LABEL: f3_2_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB31_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpne0 = icmp ne i32 %andcc, 0 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = and i1 %cmpne3, %cmpne0 + %res = select i1 %cond.inv, i64 5, i64 %x + ret i64 %res +} + +; Check 'and' with both operands select_ccmask(cc != 2). +define i64 @f3_2_2(ptr %a, i64 %x) { +; CHECK-LABEL: f3_2_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bhr %r14 +; CHECK-NEXT: .LBB32_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %ugt1 = icmp samesign ugt i32 %cc, 1 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = and i1 %ugt1, %cmpne3 + %res = select i1 %cond.inv, i64 5, i64 %x + ret i64 %res +} + +; Check 'and/tm' for (cc == 0|2). +define i64 @f3_2_3(i64 %x, ptr %a) { +; CHECK-LABEL: f3_2_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB33_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cond = icmp eq i32 %and, 0 + %res = select i1 %cond, i64 %x, i64 5 + ret i64 %res +} + +; Check 'and/tm' for (cc == 1|3). +define i64 @f3_2_4(ptr %a, i64 %x) { +; CHECK-LABEL: f3_2_4: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB34_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cond.inv = icmp eq i32 %and, 0 + %res = select i1 %cond.inv, i64 5, i64 %x + ret i64 %res +} + +; Check 'icmp' with one operand 'and' and other 'select_ccmask'(cc != 1). +define i64 @f3_2_5(i64 %x, ptr %a) { +; CHECK-LABEL: f3_2_5: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnlr %r14 +; CHECK-NEXT: .LBB35_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne3 = icmp ne i32 %cc, 3 + %cond = xor i1 %cmpne3, %trunc + %res = select i1 %cond, i64 %x, i64 5 + ret i64 %res +} + + +; Check nested 'xor' cc with select_ccmask(cc != 1). +define i64 @f3_3_1(ptr %a, i64 %x) { +; CHECK-LABEL: f3_3_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB36_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmpeq0 = icmp eq i32 %cc, 0 + %cmpeq2 = icmp eq i32 %cc, 2 + %xor = xor i1 %cmpeq0, %cmpeq2 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = xor i1 %cmpne3, %xor + %res = select i1 %cond.inv, i64 5, i64 %x + ret i64 %res +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=1). +define i64 @f3_3_2(ptr %a, i64 %x) { +; CHECK-LABEL: f3_3_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB37_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpeq3 = icmp eq i32 %cc, 3 + %cond.inv = xor i1 %cmpeq3, %trunc + %res = select i1 %cond.inv, i64 5, i64 %x + ret i64 %res +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=2). +define i64 @f3_3_3(ptr %a, i64 %x) { +; CHECK-LABEL: f3_3_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bhr %r14 +; CHECK-NEXT: .LBB38_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne0 = icmp ne i32 %cc, 0 + %cond.inv = xor i1 %cmpne0, %trunc + %res = select i1 %cond.inv, i64 5, i64 %x + ret i64 %res +} + +; Check 'or' with both operands select_ccmask with TM and ICMP(cc == 1). +define i64 @f3_4_1(ptr %a, i64 %x) { +; CHECK-LABEL: f3_4_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bnlr %r14 +; CHECK-NEXT: .LBB39_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpeq0 = icmp eq i32 %andcc, 0 + %cmpeq3 = icmp eq i32 %cc, 3 + %cond.inv = or i1 %cmpeq3, %cmpeq0 + %res = select i1 %cond.inv, i64 5, i64 %x + ret i64 %res +} + +; Check 'or' for (cc == 0|1). +define i64 @f3_4_2(ptr %a, i64 %x) { +; CHECK-LABEL: f3_4_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bnler %r14 +; CHECK-NEXT: .LBB40_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cond.inv = icmp samesign ugt i32 %or, -3 + %res = select i1 %cond.inv, i64 5, i64 %x + ret i64 %res +} + +; Check 'or' for (cc == 0|1). +define i64 @f3_4_3(i64 %x, ptr %a) { +; CHECK-LABEL: f3_4_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bler %r14 +; CHECK-NEXT: .LBB41_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cond = icmp samesign ult i32 %or, -2 + %res = select i1 %cond, i64 %x, i64 5 + ret i64 %res +} + + +; Test-4(f4_1_*/f4_2_*/f4_3_*/f4_4_*). +; TrueVal is const and FalseVal is non-const with mixed patterns involving +; Binary Ops. + +; Check 'add' for (cc != 0). +define i64 @f4_1_1(ptr %a, i64 %y) { +; CHECK-LABEL: f4_1_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: bner %r14 +; CHECK-NEXT: .LBB42_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cond = icmp ult i32 %add, 3 + %res = select i1 %cond, i64 15, i64 %y + ret i64 %res +} + +; Check 'add' for (cc == 1|2). +define i64 @f4_1_2(ptr %a, i64 %y) { +; CHECK-LABEL: f4_1_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: blhr %r14 +; CHECK-NEXT: .LBB43_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cond = icmp ult i32 %add, 2 + %res = select i1 %cond, i64 15, i64 %y + ret i64 %res +} + +; Check 'add' for (cc == 1|2). +define i64 @f4_1_3(i64 %y, ptr %a) { +; CHECK-LABEL: f4_1_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnlhr %r14 +; CHECK-NEXT: .LBB44_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -3 + %cond.inv = icmp ult i32 %add, -2 + %res = select i1 %cond.inv, i64 %y, i64 15 + ret i64 %res +} + +; Check 'and' with one operand cc and other select_ccmask(cc !=1). +define i64 @f4_2_1(i64 %y, ptr %a) { +; CHECK-LABEL: f4_2_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB45_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpne0 = icmp ne i32 %andcc, 0 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = and i1 %cmpne3, %cmpne0 + %res = select i1 %cond.inv, i64 %y, i64 15 + ret i64 %res +} + +; Check 'and' with both operands select_ccmask(cc != 2). +define i64 @f4_2_2(i64 %y, ptr %a) { +; CHECK-LABEL: f4_2_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bhr %r14 +; CHECK-NEXT: .LBB46_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %ugt1 = icmp samesign ugt i32 %cc, 1 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = and i1 %ugt1, %cmpne3 + %res = select i1 %cond.inv, i64 %y, i64 15 + ret i64 %res +} + +; Check 'and/tm' for (cc == 0|2). +define i64 @f4_2_3(ptr %a, i64 %y) { +; CHECK-LABEL: f4_2_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB47_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cond = icmp eq i32 %and, 0 + %res = select i1 %cond, i64 15, i64 %y + ret i64 %res +} + +; Check 'and/tm' for (cc == 1|3). +define i64 @f4_2_4(i64 %y, ptr %a) { +; CHECK-LABEL: f4_2_4: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB48_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cond.inv = icmp eq i32 %and, 0 + %res = select i1 %cond.inv, i64 %y, i64 15 + ret i64 %res +} + +; Check 'icmp' with one operand 'and' and other 'select_ccmask'(cc != 1). +define i64 @f4_2_5(ptr %a, i64 %y) { +; CHECK-LABEL: f4_2_5: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: bnlr %r14 +; CHECK-NEXT: .LBB49_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne3 = icmp ne i32 %cc, 3 + %cond = xor i1 %cmpne3, %trunc + %res = select i1 %cond, i64 15, i64 %y + ret i64 %res +} + + +; Check nested 'xor' cc with select_ccmask(cc != 1). +define i64 @f4_3_1(i64 %y, ptr %a) { +; CHECK-LABEL: f4_3_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB50_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmpeq0 = icmp eq i32 %cc, 0 + %cmpeq2 = icmp eq i32 %cc, 2 + %xor = xor i1 %cmpeq0, %cmpeq2 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = xor i1 %cmpne3, %xor + %res = select i1 %cond.inv, i64 %y, i64 15 + ret i64 %res +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=1). +define i64 @f4_3_2(i64 %y, ptr %a) { +; CHECK-LABEL: f4_3_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB51_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpeq3 = icmp eq i32 %cc, 3 + %cond.inv = xor i1 %cmpeq3, %trunc + %res = select i1 %cond.inv, i64 %y, i64 15 + ret i64 %res +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=2). +define i64 @f4_3_3(i64 %y, ptr %a) { +; CHECK-LABEL: f4_3_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bhr %r14 +; CHECK-NEXT: .LBB52_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne0 = icmp ne i32 %cc, 0 + %cond.inv = xor i1 %cmpne0, %trunc + %res = select i1 %cond.inv, i64 %y, i64 15 + ret i64 %res +} + +; Check 'or' with both operands select_ccmask with TM and ICMP(cc == 1). +define i64 @f4_4_1(i64 %y,ptr %a) { +; CHECK-LABEL: f4_4_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnlr %r14 +; CHECK-NEXT: .LBB53_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpeq0 = icmp eq i32 %andcc, 0 + %cmpeq3 = icmp eq i32 %cc, 3 + %cond.inv = or i1 %cmpeq3, %cmpeq0 + %res = select i1 %cond.inv, i64 %y, i64 15 + ret i64 %res +} + +; Check 'or' for (cc == 0|1). +define i64 @f4_4_2(i64 %y, ptr %a) { +; CHECK-LABEL: f4_4_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r3), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: bnler %r14 +; CHECK-NEXT: .LBB54_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cond.inv = icmp samesign ugt i32 %or, -3 + %res = select i1 %cond.inv, i64 %y, i64 15 + ret i64 %res +} + +; Check 'or' for (cc == 0|1). +define i64 @f4_4_3(ptr %a, i64 %y) { +; CHECK-LABEL: f4_4_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: bler %r14 +; CHECK-NEXT: .LBB55_1: # %entry +; CHECK-NEXT: lgr %r2, %r3 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cond = icmp samesign ult i32 %or, -2 + %res = select i1 %cond, i64 15, i64 %y + ret i64 %res +} + +; Test-5(f5_1_*/f5_2_*/f5_3_*/f5_4_*). +; Both TrueVal and FalseVal are const with mixed patterns involving +; Binary Ops. + + +; Check 'add' for (cc != 0). +define i64 @f5_1_1(ptr %a) { +; CHECK-LABEL: f5_1_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: bner %r14 +; CHECK-NEXT: .LBB56_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cond = icmp ult i32 %add, 3 + %res = select i1 %cond, i64 15, i64 5 + ret i64 %res +} + +; Check 'add' for (cc == 1|2). +define i64 @f5_1_2(ptr %a) { +; CHECK-LABEL: f5_1_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: blhr %r14 +; CHECK-NEXT: .LBB57_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -1 + %cond = icmp ult i32 %add, 2 + %res = select i1 %cond, i64 15, i64 5 + ret i64 %res +} + +; Check 'add' for (cc == 1|2). +define i64 @f5_1_3(ptr %a) { +; CHECK-LABEL: f5_1_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bnlhr %r14 +; CHECK-NEXT: .LBB58_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %add = add nsw i32 %cc, -3 + %cond.inv = icmp ult i32 %add, -2 + %res = select i1 %cond.inv, i64 5, i64 15 + ret i64 %res +} + +; Check 'and' with one operand cc and other select_ccmask(cc !=1). +define i64 @f5_2_1(ptr %a) { +; CHECK-LABEL: f5_2_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB59_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpne0 = icmp ne i32 %andcc, 0 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = and i1 %cmpne3, %cmpne0 + %res = select i1 %cond.inv, i64 5, i64 15 + ret i64 %res +} + +; Check 'and' with both operands select_ccmask(cc != 2). +define i64 @f5_2_2(ptr %a) { +; CHECK-LABEL: f5_2_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bhr %r14 +; CHECK-NEXT: .LBB60_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %ugt1 = icmp samesign ugt i32 %cc, 1 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = and i1 %ugt1, %cmpne3 + %res = select i1 %cond.inv, i64 5, i64 15 + ret i64 %res +} + +; Check 'and/tm' for (cc == 0|2). +define i64 @f5_2_3(ptr %a) { +; CHECK-LABEL: f5_2_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB61_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cond = icmp eq i32 %and, 0 + %res = select i1 %cond, i64 15, i64 5 + ret i64 %res +} + +; Check 'and/tm' for (cc == 1|3). +define i64 @f5_2_4(ptr %a) { +; CHECK-LABEL: f5_2_4: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB62_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %and = and i32 %cc, 1 + %cond.inv = icmp eq i32 %and, 0 + %res = select i1 %cond.inv, i64 5, i64 15 + ret i64 %res +} + +; Check 'icmp' with one operand 'and' and other 'select_ccmask'(cc != 1). +define i64 @f5_2_5(ptr %a) { +; CHECK-LABEL: f5_2_5: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: bnlr %r14 +; CHECK-NEXT: .LBB63_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne3 = icmp ne i32 %cc, 3 + %cond = xor i1 %cmpne3, %trunc + %res = select i1 %cond, i64 15, i64 5 + ret i64 %res +} + + +; Check nested 'xor' cc with select_ccmask(cc != 1). +define i64 @f5_3_1(ptr %a) { +; CHECK-LABEL: f5_3_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB64_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %cmpeq0 = icmp eq i32 %cc, 0 + %cmpeq2 = icmp eq i32 %cc, 2 + %xor = xor i1 %cmpeq0, %cmpeq2 + %cmpne3 = icmp ne i32 %cc, 3 + %cond.inv = xor i1 %cmpne3, %xor + %res = select i1 %cond.inv, i64 5, i64 15 + ret i64 %res +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=1). +define i64 @f5_3_2(ptr %a) { +; CHECK-LABEL: f5_3_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: blr %r14 +; CHECK-NEXT: .LBB65_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpeq3 = icmp eq i32 %cc, 3 + %cond.inv = xor i1 %cmpeq3, %trunc + %res = select i1 %cond.inv, i64 5, i64 15 + ret i64 %res +} + +; Check branching on 'tm' and 'xor' with one operand cc and the other +; select_ccmask(cc !=2). +define i64 @f5_3_3(ptr %a) { +; CHECK-LABEL: f5_3_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bhr %r14 +; CHECK-NEXT: .LBB66_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %trunc = trunc i32 %cc to i1 + %cmpne0 = icmp ne i32 %cc, 0 + %cond.inv = xor i1 %cmpne0, %trunc + %res = select i1 %cond.inv, i64 5, i64 15 + ret i64 %res +} + +; Check 'or' with both operands select_ccmask with TM and ICMP(cc == 1). +define i64 @f5_4_1(ptr %a) { +; CHECK-LABEL: f5_4_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bnlr %r14 +; CHECK-NEXT: .LBB67_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %andcc = and i32 %cc, 1 + %cmpeq0 = icmp eq i32 %andcc, 0 + %cmpeq3 = icmp eq i32 %cc, 3 + %cond.inv = or i1 %cmpeq3, %cmpeq0 + %res = select i1 %cond.inv, i64 5, i64 15 + ret i64 %res +} + +; Check 'or' for (cc == 0|1). +define i64 @f5_4_2(ptr %a) { +; CHECK-LABEL: f5_4_2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: bnler %r14 +; CHECK-NEXT: .LBB68_1: # %entry +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cond.inv = icmp samesign ugt i32 %or, -3 + %res = select i1 %cond.inv, i64 5, i64 15 + ret i64 %res +} + +; Check 'or' for (cc == 0|1). +define i64 @f5_4_3(ptr %a) { +; CHECK-LABEL: f5_4_3: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: bler %r14 +; CHECK-NEXT: .LBB69_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %tmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %tmp) + %or = or disjoint i32 %cc, -4 + %cond = icmp samesign ult i32 %or, -2 + %res = select i1 %cond, i64 15, i64 5 + ret i64 %res +} + +; Nested select_ccmask with TrueVal and FalseVal swapped with each other. +define i64 @f6_1(ptr %a) { +; CHECK-LABEL: f6_1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: #APP +; CHECK-NEXT: alsi 0(%r2), -1 +; CHECK-EMPTY: +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: lghi %r2, 15 +; CHECK-NEXT: bher %r14 +; CHECK-NEXT: .LBB70_1: # %entry +; CHECK-NEXT: lghi %r2, 5 +; CHECK-NEXT: br %r14 +entry: + %cc = tail call i32 asm sideeffect "alsi $1,-1\0A", "={@cc},=*QS,*QS,~{memory}"(ptr elementtype(i32) %a, ptr elementtype(i32) %a) + %cmp = icmp ult i32 %cc, 4 + tail call void @llvm.assume(i1 %cmp) + %andcc = and i32 %cc, 1 + %cmpeq0 = icmp eq i32 %andcc, 0 + %cmpeq3 = icmp eq i32 %cc, 3 + %select = select i1 %cmpeq3, i64 5, i64 15 + %res = select i1 %cmpeq0, i64 %select, i64 5 + ret i64 %res +} +