Index: llvm/include/llvm/CodeGen/TargetLowering.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLowering.h +++ llvm/include/llvm/CodeGen/TargetLowering.h @@ -3647,6 +3647,12 @@ std::vector &Ops, SelectionDAG &DAG) const; + // Lower custom output constraints. If invalid, return SDValue(). + virtual SDValue LowerAsmOutputForConstraint(SDValue &Chain, SDValue *Flag, + SDLoc DL, + const AsmOperandInfo &OpInfo, + SelectionDAG &DAG) const; + //===--------------------------------------------------------------------===// // Div utility functions // Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -7679,11 +7679,9 @@ switch (OpInfo.Type) { case InlineAsm::isOutput: - if (OpInfo.ConstraintType != TargetLowering::C_RegisterClass && - OpInfo.ConstraintType != TargetLowering::C_Register) { - // Memory output, or 'other' output (e.g. 'X' constraint). - assert(OpInfo.isIndirect && "Memory output must be indirect operand"); - + if (OpInfo.ConstraintType == TargetLowering::C_Memory || + (OpInfo.ConstraintType == TargetLowering::C_Other && + OpInfo.isIndirect)) { unsigned ConstraintID = TLI.getInlineAsmMemConstraint(OpInfo.ConstraintCode); assert(ConstraintID != InlineAsm::Constraint_Unknown && @@ -7696,12 +7694,13 @@ MVT::i32)); AsmNodeOperands.push_back(OpInfo.CallOperand); break; - } else if (OpInfo.ConstraintType == TargetLowering::C_Register || + } else if ((OpInfo.ConstraintType == TargetLowering::C_Other && + !OpInfo.isIndirect) || + OpInfo.ConstraintType == TargetLowering::C_Register || OpInfo.ConstraintType == TargetLowering::C_RegisterClass) { - // Otherwise, this is a register or register class output. - - // Copy the output from the appropriate register. Find a register that - // we can use. + // Otherwise, this outputs to a register (directly for C_Register / + // C_RegisterClass, and a target-defined fashion for C_Other). Find a + // register that we can use. if (OpInfo.AssignedRegs.Regs.empty()) { emitInlineAsmError( CS, "couldn't allocate output register for constraint '" + @@ -7917,25 +7916,41 @@ ResultValues.push_back(V); }; - // Deal with assembly output fixups. + // Deal with output operands. for (SDISelAsmOperandInfo &OpInfo : ConstraintOperands) { - if (OpInfo.Type == InlineAsm::isOutput && - (OpInfo.ConstraintType == TargetLowering::C_Register || - OpInfo.ConstraintType == TargetLowering::C_RegisterClass)) { + if (OpInfo.Type == InlineAsm::isOutput) { + SDValue Val; + // Skip trivial output operands. + if (OpInfo.AssignedRegs.Regs.empty()) + continue; + + switch (OpInfo.ConstraintType) { + case TargetLowering::C_Register: + case TargetLowering::C_RegisterClass: + Val = OpInfo.AssignedRegs.getCopyFromRegs( + DAG, FuncInfo, getCurSDLoc(), Chain, &Flag, CS.getInstruction()); + break; + case TargetLowering::C_Other: + Val = TLI.LowerAsmOutputForConstraint(Chain, &Flag, getCurSDLoc(), + OpInfo, DAG); + break; + case TargetLowering::C_Memory: + break; // Already handled. + case TargetLowering::C_Unknown: + assert(false && "Unexpected unknown constraint"); + } + + // Indirect output manifest as stores. Record output chains. if (OpInfo.isIndirect) { - // Register indirect are manifest as stores. - const RegsForValue &OutRegs = OpInfo.AssignedRegs; + const Value *Ptr = OpInfo.CallOperandVal; - SDValue OutVal = OutRegs.getCopyFromRegs(DAG, FuncInfo, getCurSDLoc(), - Chain, &Flag, IA); - SDValue Val = DAG.getStore(Chain, getCurSDLoc(), OutVal, getValue(Ptr), - MachinePointerInfo(Ptr)); - OutChains.push_back(Val); + assert(Ptr && "Expected value CallOperandVal for indirect asm operand"); + SDValue Store = DAG.getStore(Chain, getCurSDLoc(), Val, getValue(Ptr), + MachinePointerInfo(Ptr)); + OutChains.push_back(Store); } else { // generate CopyFromRegs to associated registers. assert(!CS.getType()->isVoidTy() && "Bad inline asm!"); - SDValue Val = OpInfo.AssignedRegs.getCopyFromRegs( - DAG, FuncInfo, getCurSDLoc(), Chain, &Flag, CS.getInstruction()); if (Val.getOpcode() == ISD::MERGE_VALUES) { for (const SDValue &V : Val->op_values()) handleRegAssign(V); Index: llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -3177,6 +3177,12 @@ return nullptr; } +SDValue TargetLowering::LowerAsmOutputForConstraint( + SDValue &Chain, SDValue *Flag, SDLoc DL, const AsmOperandInfo &OpInfo, + SelectionDAG &DAG) const { + return SDValue(); +} + /// Lower the specified operand into the Ops vector. /// If it is invalid, don't add anything to Ops. void TargetLowering::LowerAsmOperandForConstraint(SDValue Op, Index: llvm/lib/Target/X86/X86ISelLowering.h =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.h +++ llvm/lib/Target/X86/X86ISelLowering.h @@ -923,6 +923,11 @@ return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); } + /// Handle Lowering flag assembly outputs. + SDValue LowerAsmOutputForConstraint(SDValue &Chain, SDValue *Flag, SDLoc DL, + const AsmOperandInfo &Constraint, + SelectionDAG &DAG) const override; + /// Given a physical register constraint /// (e.g. {edx}), return the register number and the register class for the /// register. This should only be used for C_Register constraints. On Index: llvm/lib/Target/X86/X86ISelLowering.cpp =================================================================== --- llvm/lib/Target/X86/X86ISelLowering.cpp +++ llvm/lib/Target/X86/X86ISelLowering.cpp @@ -42255,6 +42255,40 @@ return false; } +static X86::CondCode parseConstraintCode(llvm::StringRef Constraint) { + X86::CondCode Cond = StringSwitch(Constraint) + .Case("{@cca}", X86::COND_A) + .Case("{@ccae}", X86::COND_AE) + .Case("{@ccb}", X86::COND_B) + .Case("{@ccbe}", X86::COND_BE) + .Case("{@ccc}", X86::COND_B) + .Case("{@cce}", X86::COND_E) + .Case("{@ccz}", X86::COND_NE) + .Case("{@ccg}", X86::COND_G) + .Case("{@ccge}", X86::COND_GE) + .Case("{@ccl}", X86::COND_L) + .Case("{@ccle}", X86::COND_LE) + .Case("{@ccna}", X86::COND_BE) + .Case("{@ccnae}", X86::COND_B) + .Case("{@ccnb}", X86::COND_AE) + .Case("{@ccnbe}", X86::COND_A) + .Case("{@ccnc}", X86::COND_AE) + .Case("{@ccne}", X86::COND_NE) + .Case("{@ccnz}", X86::COND_NE) + .Case("{@ccng}", X86::COND_LE) + .Case("{@ccnge}", X86::COND_L) + .Case("{@ccnl}", X86::COND_GE) + .Case("{@ccnle}", X86::COND_G) + .Case("{@ccno}", X86::COND_NO) + .Case("{@ccnp}", X86::COND_P) + .Case("{@ccns}", X86::COND_NS) + .Case("{@cco}", X86::COND_O) + .Case("{@ccp}", X86::COND_P) + .Case("{@ccs}", X86::COND_S) + .Default(X86::COND_INVALID); + return Cond; +} + /// Given a constraint letter, return the type of constraint for this target. X86TargetLowering::ConstraintType X86TargetLowering::getConstraintType(StringRef Constraint) const { @@ -42315,7 +42349,8 @@ return C_RegisterClass; } } - } + } else if (parseConstraintCode(Constraint) != X86::COND_INVALID) + return C_Other; return TargetLowering::getConstraintType(Constraint); } @@ -42486,6 +42521,33 @@ return TargetLowering::LowerXConstraint(ConstraintVT); } +// Lower @cc targets via setcc. +SDValue X86TargetLowering::LowerAsmOutputForConstraint( + SDValue &Chain, SDValue *Flag, SDLoc DL, const AsmOperandInfo &OpInfo, + SelectionDAG &DAG) const { + X86::CondCode Cond = parseConstraintCode(OpInfo.ConstraintCode); + if (Cond == X86::COND_INVALID) + return SDValue(); + // Check that return type is valid. + if (OpInfo.ConstraintVT.isVector() || !OpInfo.ConstraintVT.isInteger() || + OpInfo.ConstraintVT.getSizeInBits() < 8) + report_fatal_error("Flag output operand is of invalid type"); + + // Get EFLAGS register. Only update chain when copyfrom is glued. + SDValue EFlags; + if (Flag) { + EFlags = DAG.getCopyFromReg(Chain, DL, X86::EFLAGS, MVT::i32, *Flag); + Chain = EFlags.getValue(1); + } else + EFlags = DAG.getCopyFromReg(Chain, DL, X86::EFLAGS, MVT::i32); + // Extract CC code. + SDValue CC = getSETCC(Cond, EFlags, DL, DAG); + // Extend to 32-bits + SDValue Result = DAG.getNode(ISD::ZERO_EXTEND, DL, OpInfo.ConstraintVT, CC); + + return Result; +} + /// Lower the specified operand into the Ops vector. /// If it is invalid, don't add anything to Ops. void X86TargetLowering::LowerAsmOperandForConstraint(SDValue Op, @@ -42842,6 +42904,9 @@ } } + if (parseConstraintCode(Constraint) != X86::COND_INVALID) + return std::make_pair(0U, &X86::GR32RegClass); + // Use the default implementation in TargetLowering to convert the register // constraint into a member of a register class. std::pair Res; Index: llvm/test/CodeGen/X86/inline-asm-flag-output.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/X86/inline-asm-flag-output.ll @@ -0,0 +1,954 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=i686-- -no-integrated-as | FileCheck %s -check-prefix=X32 +; RUN: llc < %s -mtriple=x86_64-- -no-integrated-as | FileCheck %s -check-prefix=X64 + +define i32 @test_cca(i64 %nr, i64* %addr) { +; X32-LABEL: test_cca: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setbe %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_cca: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setbe %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@cca},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccae(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccae: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setb %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccae: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setb %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccae},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccb(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccb: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setae %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccb: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setae %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccb},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccbe(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccbe: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: seta %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccbe: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: seta %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccbe},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccc(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccc: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setae %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccc: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setae %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccc},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_cce(i64 %nr, i64* %addr) { +; X32-LABEL: test_cce: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setne %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_cce: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setne %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@cce},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccz(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccz: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: sete %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccz: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: sete %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccz},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccg(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccg: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setle %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccg: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setle %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccg},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccge(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccge: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setl %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccge: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setl %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccge},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccl(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccl: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setge %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccl: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setge %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccl},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccle(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccle: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setg %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccle: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setg %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccle},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccna(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccna: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: seta %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccna: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: seta %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccna},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccnae(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccnae: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setae %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccnae: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setae %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccnae},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccnb(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccnb: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setb %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccnb: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setb %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccnb},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccnbe(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccnbe: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setbe %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccnbe: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setbe %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccnbe},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccnc(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccnc: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setb %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccnc: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setb %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccnc},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccne(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccne: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: sete %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccne: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: sete %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccne},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccnz(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccnz: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: sete %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccnz: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: sete %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccnz},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccng(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccng: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setg %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccng: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setg %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccng},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccnge(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccnge: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setge %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccnge: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setge %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccnge},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccnl(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccnl: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setl %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccnl: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setl %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccnl},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccnle(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccnle: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setle %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccnle: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setle %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccnle},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccno(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccno: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: seto %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccno: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: seto %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccno},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccnp(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccnp: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setnp %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccnp: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setnp %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccnp},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccns(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccns: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: sets %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccns: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: sets %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccns},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_cco(i64 %nr, i64* %addr) { +; X32-LABEL: test_cco: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setno %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_cco: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setno %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@cco},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccp(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccp: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setnp %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccp: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setnp %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccp},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +} + + +define i32 @test_ccs(i64 %nr, i64* %addr) { +; X32-LABEL: test_ccs: +; X32: # %bb.0: # %entry +; X32-NEXT: pushl %esi +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: .cfi_offset %esi, -8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx +; X32-NEXT: movl {{[0-9]+}}(%esp), %edx +; X32-NEXT: movl {{[0-9]+}}(%esp), %esi +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: #APP +; X32-NEXT: cmp %ecx,(%esi) +; X32-NEXT: #NO_APP +; X32-NEXT: setns %al +; X32-NEXT: popl %esi +; X32-NEXT: .cfi_def_cfa_offset 4 +; X32-NEXT: retl +; +; X64-LABEL: test_ccs: +; X64: # %bb.0: # %entry +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: #APP +; X64-NEXT: cmp %rdi,(%rsi) +; X64-NEXT: #NO_APP +; X64-NEXT: setns %al +; X64-NEXT: retq +entry: + %cc = tail call i32 asm "cmp $2,$1", "={@ccs},=*m,r,~{cc},~{dirflag},~{fpsr},~{flags}"(i64* %addr, i64 %nr) nounwind + %tobool = icmp eq i32 %cc, 0 + %rv = zext i1 %tobool to i32 + ret i32 %rv +}