diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.h b/llvm/lib/Target/Sparc/SparcISelLowering.h --- a/llvm/lib/Target/Sparc/SparcISelLowering.h +++ b/llvm/lib/Target/Sparc/SparcISelLowering.h @@ -21,37 +21,39 @@ class SparcSubtarget; namespace SPISD { - enum NodeType : unsigned { - FIRST_NUMBER = ISD::BUILTIN_OP_END, - CMPICC, // Compare two GPR operands, set icc+xcc. - CMPFCC, // Compare two FP operands, set fcc. - BRICC, // Branch to dest on icc condition - BRXCC, // Branch to dest on xcc condition (64-bit only). - BRFCC, // Branch to dest on fcc condition - SELECT_ICC, // Select between two values using the current ICC flags. - SELECT_XCC, // Select between two values using the current XCC flags. - SELECT_FCC, // Select between two values using the current FCC flags. - - Hi, Lo, // Hi/Lo operations, typically on a global address. - - FTOI, // FP to Int within a FP register. - ITOF, // Int to FP within a FP register. - FTOX, // FP to Int64 within a FP register. - XTOF, // Int64 to FP within a FP register. - - CALL, // A call instruction. - RET_FLAG, // Return with a flag operand. - GLOBAL_BASE_REG, // Global base reg for PIC. - FLUSHW, // FLUSH register windows to stack. - - TAIL_CALL, // Tail call - - TLS_ADD, // For Thread Local Storage (TLS). - TLS_LD, - TLS_CALL, - - LOAD_GDOP, // Load operation w/ gdop relocation. - }; + enum NodeType : unsigned { + FIRST_NUMBER = ISD::BUILTIN_OP_END, + CMPICC, // Compare two GPR operands, set icc+xcc. + CMPFCC, // Compare two FP operands, set fcc. + BRICC, // Branch to dest on icc condition + BPICC, // Branch to dest on icc condition, with prediction (64-bit only). + BPXCC, // Branch to dest on xcc condition, with prediction (64-bit only). + BRFCC, // Branch to dest on fcc condition + SELECT_ICC, // Select between two values using the current ICC flags. + SELECT_XCC, // Select between two values using the current XCC flags. + SELECT_FCC, // Select between two values using the current FCC flags. + + Hi, + Lo, // Hi/Lo operations, typically on a global address. + + FTOI, // FP to Int within a FP register. + ITOF, // Int to FP within a FP register. + FTOX, // FP to Int64 within a FP register. + XTOF, // Int64 to FP within a FP register. + + CALL, // A call instruction. + RET_FLAG, // Return with a flag operand. + GLOBAL_BASE_REG, // Global base reg for PIC. + FLUSHW, // FLUSH register windows to stack. + + TAIL_CALL, // Tail call + + TLS_ADD, // For Thread Local Storage (TLS). + TLS_LD, + TLS_CALL, + + LOAD_GDOP, // Load operation w/ gdop relocation. + }; } class SparcTargetLowering : public TargetLowering { diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp --- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp +++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp @@ -1928,7 +1928,10 @@ case SPISD::CMPICC: return "SPISD::CMPICC"; case SPISD::CMPFCC: return "SPISD::CMPFCC"; case SPISD::BRICC: return "SPISD::BRICC"; - case SPISD::BRXCC: return "SPISD::BRXCC"; + case SPISD::BPICC: + return "SPISD::BPICC"; + case SPISD::BPXCC: + return "SPISD::BPXCC"; case SPISD::BRFCC: return "SPISD::BRFCC"; case SPISD::SELECT_ICC: return "SPISD::SELECT_ICC"; case SPISD::SELECT_XCC: return "SPISD::SELECT_XCC"; @@ -2533,8 +2536,8 @@ } static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG, - const SparcTargetLowering &TLI, - bool hasHardQuad) { + const SparcTargetLowering &TLI, bool hasHardQuad, + bool isV9) { SDValue Chain = Op.getOperand(0); ISD::CondCode CC = cast(Op.getOperand(1))->get(); SDValue LHS = Op.getOperand(2); @@ -2552,13 +2555,17 @@ if (LHS.getValueType().isInteger()) { CompareFlag = DAG.getNode(SPISD::CMPICC, dl, MVT::Glue, LHS, RHS); if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC); - // 32-bit compares use the icc flags, 64-bit uses the xcc flags. - Opc = LHS.getValueType() == MVT::i32 ? SPISD::BRICC : SPISD::BRXCC; + if (isV9) + // 32-bit compares use the icc flags, 64-bit uses the xcc flags. + Opc = LHS.getValueType() == MVT::i32 ? SPISD::BPICC : SPISD::BPXCC; + else + // Non-v9 targets don't have xcc. + Opc = SPISD::BRICC; } else { if (!hasHardQuad && LHS.getValueType() == MVT::f128) { if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG); - Opc = SPISD::BRICC; + Opc = isV9 ? SPISD::BPICC : SPISD::BRICC; } else { CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS); if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC); @@ -3141,8 +3148,8 @@ hasHardQuad); case ISD::UINT_TO_FP: return LowerUINT_TO_FP(Op, DAG, *this, hasHardQuad); - case ISD::BR_CC: return LowerBR_CC(Op, DAG, *this, - hasHardQuad); + case ISD::BR_CC: + return LowerBR_CC(Op, DAG, *this, hasHardQuad, isV9); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, *this, hasHardQuad); case ISD::VASTART: return LowerVASTART(Op, DAG, *this); @@ -3221,6 +3228,8 @@ case SP::SELECT_CC_FP_ICC: case SP::SELECT_CC_DFP_ICC: case SP::SELECT_CC_QFP_ICC: + if (Subtarget->isV9()) + return expandSelectCC(MI, BB, SP::BPICC); return expandSelectCC(MI, BB, SP::BCOND); case SP::SELECT_CC_Int_XCC: case SP::SELECT_CC_FP_XCC: diff --git a/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/llvm/lib/Target/Sparc/SparcInstr64Bit.td --- a/llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ b/llvm/lib/Target/Sparc/SparcInstr64Bit.td @@ -310,13 +310,13 @@ // The icc flags correspond to the 32-bit result, and the xcc are for the // full 64-bit result. // -// We reuse CMPICC SDNodes for compares, but use new BRXCC branch nodes for +// We reuse CMPICC SDNodes for compares, but use new BPXCC branch nodes for // 64-bit compares. See LowerBR_CC. let Predicates = [Is64Bit] in { let Uses = [ICC], cc = 0b10 in - defm BPX : IPredBranch<"%xcc", [(SPbrxcc bb:$imm19, imm:$cond)]>; + defm BPX : IPredBranch<"%xcc", [(SPbpxcc bb:$imm19, imm:$cond)]>; // Conditional moves on %xcc. let Uses = [ICC], Constraints = "$f = $rd" in { diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp --- a/llvm/lib/Target/Sparc/SparcInstrInfo.cpp +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.cpp @@ -140,10 +140,25 @@ llvm_unreachable("Invalid cond code"); } -static bool isUncondBranchOpcode(int Opc) { return Opc == SP::BA; } +static bool isUncondBranchOpcode(int Opc) { + return Opc == SP::BA || Opc == SP::BPA; +} + +static bool isI32CondBranchOpcode(int Opc) { + return Opc == SP::BCOND || Opc == SP::BPICC || Opc == SP::BPICCA || + Opc == SP::BPICCNT || Opc == SP::BPICCANT; +} + +static bool isI64CondBranchOpcode(int Opc) { + return Opc == SP::BPXCC || Opc == SP::BPXCCA || Opc == SP::BPXCCNT || + Opc == SP::BPXCCANT; +} + +static bool isFCondBranchOpcode(int Opc) { return Opc == SP::FBCOND; } static bool isCondBranchOpcode(int Opc) { - return Opc == SP::FBCOND || Opc == SP::BCOND; + return isI32CondBranchOpcode(Opc) || isI64CondBranchOpcode(Opc) || + isFCondBranchOpcode(Opc); } static bool isIndirectBranchOpcode(int Opc) { @@ -152,7 +167,14 @@ static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target, SmallVectorImpl &Cond) { - Cond.push_back(MachineOperand::CreateImm(LastInst->getOperand(1).getImm())); + unsigned Opc = LastInst->getOpcode(); + int64_t CC = LastInst->getOperand(1).getImm(); + + // Push the branch opcode into Cond too so later in insertBranch + // it can use the information to emit the correct SPARC branch opcode. + Cond.push_back(MachineOperand::CreateImm(Opc)); + Cond.push_back(MachineOperand::CreateImm(CC)); + Target = LastInst->getOperand(0).getMBB(); } @@ -246,27 +268,29 @@ const DebugLoc &DL, int *BytesAdded) const { assert(TBB && "insertBranch must not be told to insert a fallthrough"); - assert((Cond.size() == 1 || Cond.size() == 0) && - "Sparc branch conditions should have one component!"); + assert((Cond.size() <= 2) && + "Sparc branch conditions should have at most two components!"); assert(!BytesAdded && "code size not handled"); if (Cond.empty()) { assert(!FBB && "Unconditional branch with multiple successors!"); - BuildMI(&MBB, DL, get(SP::BA)).addMBB(TBB); + BuildMI(&MBB, DL, get(Subtarget.isV9() ? SP::BPA : SP::BA)).addMBB(TBB); return 1; } // Conditional branch - unsigned CC = Cond[0].getImm(); + unsigned Opc = Cond[0].getImm(); + unsigned CC = Cond[1].getImm(); - if (IsIntegerCC(CC)) - BuildMI(&MBB, DL, get(SP::BCOND)).addMBB(TBB).addImm(CC); - else + if (IsIntegerCC(CC)) { + BuildMI(&MBB, DL, get(Opc)).addMBB(TBB).addImm(CC); + } else { BuildMI(&MBB, DL, get(SP::FBCOND)).addMBB(TBB).addImm(CC); + } if (!FBB) return 1; - BuildMI(&MBB, DL, get(SP::BA)).addMBB(FBB); + BuildMI(&MBB, DL, get(Subtarget.isV9() ? SP::BPA : SP::BA)).addMBB(FBB); return 2; } @@ -282,9 +306,8 @@ if (I->isDebugInstr()) continue; - if (I->getOpcode() != SP::BA - && I->getOpcode() != SP::BCOND - && I->getOpcode() != SP::FBCOND) + if (!isCondBranchOpcode(I->getOpcode()) && + !isUncondBranchOpcode(I->getOpcode())) break; // Not a branch I->eraseFromParent(); @@ -296,9 +319,9 @@ bool SparcInstrInfo::reverseBranchCondition( SmallVectorImpl &Cond) const { - assert(Cond.size() == 1); - SPCC::CondCodes CC = static_cast(Cond[0].getImm()); - Cond[0].setImm(GetOppositeBranchCondition(CC)); + assert(Cond.size() <= 2); + SPCC::CondCodes CC = static_cast(Cond[1].getImm()); + Cond[1].setImm(GetOppositeBranchCondition(CC)); return false; } diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td --- a/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -242,7 +242,8 @@ def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>; def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>; def SPbricc : SDNode<"SPISD::BRICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; -def SPbrxcc : SDNode<"SPISD::BRXCC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; +def SPbpicc : SDNode<"SPISD::BPICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; +def SPbpxcc : SDNode<"SPISD::BPXCC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; def SPbrfcc : SDNode<"SPISD::BRFCC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; def SPhi : SDNode<"SPISD::Hi", SDTIntUnaryOp>; @@ -845,19 +846,27 @@ defm RESTORE : F3_12np<"restore", 0b111101>; // Section B.21 - Branch on Integer Condition Codes Instructions, p. 119 +// Section A.7 - Branch on Integer Condition Codes with Prediction (SPARC v9) +let isBranch = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in { // unconditional branch class. class BranchAlways pattern> - : F2_2<0b010, 0, (outs), ins, asmstr, pattern> { - let isBranch = 1; - let isTerminator = 1; - let hasDelaySlot = 1; - let isBarrier = 1; + : F2_2<0b010, 0, (outs), ins, asmstr, pattern>; + +// Same as BranchAlways but uses the new v9 encoding +class BranchPredictAlways pattern> + : F2_3<0b001, 0, 1, (outs), ins, asmstr, pattern>; } -let cond = 8 in - def BA : BranchAlways<(ins brtarget:$imm22), "ba $imm22", [(br bb:$imm22)]>; +let cond = 8 in { + // If we're compiling for v9, prefer BPA rather than BA + // TODO: Disallow BA emission when FeatureV8Deprecated isn't enabled + let Predicates = [HasV9], cc = 0b00 in + def BPA : BranchPredictAlways<(ins bprtarget:$imm19), + "ba %icc, $imm19", [(br bb:$imm19)]>; + def BA : BranchAlways<(ins brtarget:$imm22), "ba $imm22", [(br bb:$imm22)]>; +} let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in { @@ -913,7 +922,7 @@ "b$cond,a $imm22", []>; let Predicates = [HasV9], cc = 0b00 in - defm BPI : IPredBranch<"%icc", []>; + defm BPI : IPredBranch<"%icc", [(SPbpicc bb:$imm19, imm:$cond)]>; } // Section B.22 - Branch on Floating-point Condition Codes Instructions, p. 121 diff --git a/llvm/test/CodeGen/SPARC/atomics.ll b/llvm/test/CodeGen/SPARC/atomics.ll --- a/llvm/test/CodeGen/SPARC/atomics.ll +++ b/llvm/test/CodeGen/SPARC/atomics.ll @@ -1,13 +1,20 @@ -; RUN: llc < %s -march=sparc -mcpu=v9 -verify-machineinstrs | FileCheck %s -; RUN: llc < %s -march=sparcv9 -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -march=sparc -mcpu=v9 -verify-machineinstrs | FileCheck %s --check-prefixes=SPARC +; RUN: llc < %s -march=sparcv9 -verify-machineinstrs | FileCheck %s --check-prefixes=SPARC64 -; CHECK-LABEL: test_atomic_i8 -; CHECK: ldub [%o0] -; CHECK: membar -; CHECK: ldub [%o1] -; CHECK: membar -; CHECK: membar -; CHECK: stb {{.+}}, [%o2] +; SPARC-LABEL: test_atomic_i8 +; SPARC: ldub [%o0] +; SPARC: membar +; SPARC: ldub [%o1] +; SPARC: membar +; SPARC: membar +; SPARC: stb {{.+}}, [%o2] +; SPARC64-LABEL: test_atomic_i8 +; SPARC64: ldub [%o0] +; SPARC64: membar +; SPARC64: ldub [%o1] +; SPARC64: membar +; SPARC64: membar +; SPARC64: stb {{.+}}, [%o2] define i8 @test_atomic_i8(i8* %ptr1, i8* %ptr2, i8* %ptr3) { entry: %0 = load atomic i8, i8* %ptr1 acquire, align 1 @@ -17,13 +24,20 @@ ret i8 %2 } -; CHECK-LABEL: test_atomic_i16 -; CHECK: lduh [%o0] -; CHECK: membar -; CHECK: lduh [%o1] -; CHECK: membar -; CHECK: membar -; CHECK: sth {{.+}}, [%o2] +; SPARC-LABEL: test_atomic_i16 +; SPARC: lduh [%o0] +; SPARC: membar +; SPARC: lduh [%o1] +; SPARC: membar +; SPARC: membar +; SPARC: sth {{.+}}, [%o2] +; SPARC64-LABEL: test_atomic_i16 +; SPARC64: lduh [%o0] +; SPARC64: membar +; SPARC64: lduh [%o1] +; SPARC64: membar +; SPARC64: membar +; SPARC64: sth {{.+}}, [%o2] define i16 @test_atomic_i16(i16* %ptr1, i16* %ptr2, i16* %ptr3) { entry: %0 = load atomic i16, i16* %ptr1 acquire, align 2 @@ -33,13 +47,20 @@ ret i16 %2 } -; CHECK-LABEL: test_atomic_i32 -; CHECK: ld [%o0] -; CHECK: membar -; CHECK: ld [%o1] -; CHECK: membar -; CHECK: membar -; CHECK: st {{.+}}, [%o2] +; SPARC-LABEL: test_atomic_i32 +; SPARC: ld [%o0] +; SPARC: membar +; SPARC: ld [%o1] +; SPARC: membar +; SPARC: membar +; SPARC: st {{.+}}, [%o2] +; SPARC64-LABEL: test_atomic_i32 +; SPARC64: ld [%o0] +; SPARC64: membar +; SPARC64: ld [%o1] +; SPARC64: membar +; SPARC64: membar +; SPARC64: st {{.+}}, [%o2] define i32 @test_atomic_i32(i32* %ptr1, i32* %ptr2, i32* %ptr3) { entry: %0 = load atomic i32, i32* %ptr1 acquire, align 4 @@ -53,38 +74,70 @@ ;; redundant here. There's something weird happening in optimization ;; of the success value of cmpxchg. -; CHECK-LABEL: test_cmpxchg_i8 -; CHECK: and %o1, -4, %o2 -; CHECK: mov 3, %o3 -; CHECK: andn %o3, %o1, %o1 -; CHECK: sll %o1, 3, %o1 -; CHECK: mov 255, %o3 -; CHECK: sll %o3, %o1, %o5 -; CHECK: xor %o5, -1, %o3 -; CHECK: mov 123, %o4 -; CHECK: ld [%o2], %g2 -; CHECK: sll %o4, %o1, %o4 -; CHECK: and %o0, 255, %o0 -; CHECK: sll %o0, %o1, %o0 -; CHECK: andn %g2, %o5, %g2 -; CHECK: mov %g0, %o5 -; CHECK: [[LABEL1:\.L.*]]: -; CHECK: or %g2, %o4, %g3 -; CHECK: or %g2, %o0, %g4 -; CHECK: cas [%o2], %g4, %g3 -; CHECK: cmp %g3, %g4 -; CHECK: mov %o5, %g4 -; CHECK: move %icc, 1, %g4 -; CHECK: cmp %g4, 0 -; CHECK: bne [[LABEL2:\.L.*]] -; CHECK: nop -; CHECK: and %g3, %o3, %g4 -; CHECK: cmp %g2, %g4 -; CHECK: bne [[LABEL1]] -; CHECK: mov %g4, %g2 -; CHECK: [[LABEL2]]: -; CHECK: retl -; CHECK: srl %g3, %o1, %o0 +; SPARC-LABEL: test_cmpxchg_i8 +; SPARC: and %o1, -4, %o2 +; SPARC: mov 3, %o3 +; SPARC: andn %o3, %o1, %o1 +; SPARC: sll %o1, 3, %o1 +; SPARC: mov 255, %o3 +; SPARC: sll %o3, %o1, %o5 +; SPARC: xor %o5, -1, %o3 +; SPARC: mov 123, %o4 +; SPARC: ld [%o2], %g2 +; SPARC: sll %o4, %o1, %o4 +; SPARC: and %o0, 255, %o0 +; SPARC: sll %o0, %o1, %o0 +; SPARC: andn %g2, %o5, %g2 +; SPARC: mov %g0, %o5 +; SPARC: [[LABEL1:\.L.*]]: +; SPARC: or %g2, %o4, %g3 +; SPARC: or %g2, %o0, %g4 +; SPARC: cas [%o2], %g4, %g3 +; SPARC: cmp %g3, %g4 +; SPARC: mov %o5, %g4 +; SPARC: move %icc, 1, %g4 +; SPARC: cmp %g4, 0 +; SPARC: bne %icc, [[LABEL2:\.L.*]] +; SPARC: nop +; SPARC: and %g3, %o3, %g4 +; SPARC: cmp %g2, %g4 +; SPARC: bne %icc, [[LABEL1]] +; SPARC: mov %g4, %g2 +; SPARC: [[LABEL2]]: +; SPARC: retl +; SPARC: srl %g3, %o1, %o0 +; SPARC64-LABEL: test_cmpxchg_i8 +; SPARC64: and %o1, -4, %o2 +; SPARC64: mov 3, %o3 +; SPARC64: andn %o3, %o1, %o1 +; SPARC64: sll %o1, 3, %o1 +; SPARC64: mov 255, %o3 +; SPARC64: sll %o3, %o1, %o5 +; SPARC64: xor %o5, -1, %o3 +; SPARC64: mov 123, %o4 +; SPARC64: ld [%o2], %g2 +; SPARC64: sll %o4, %o1, %o4 +; SPARC64: and %o0, 255, %o0 +; SPARC64: sll %o0, %o1, %o0 +; SPARC64: andn %g2, %o5, %g2 +; SPARC64: mov %g0, %o5 +; SPARC64: [[LABEL1:\.L.*]]: +; SPARC64: or %g2, %o4, %g3 +; SPARC64: or %g2, %o0, %g4 +; SPARC64: cas [%o2], %g4, %g3 +; SPARC64: cmp %g3, %g4 +; SPARC64: mov %o5, %g4 +; SPARC64: move %icc, 1, %g4 +; SPARC64: cmp %g4, 0 +; SPARC64: bne %icc, [[LABEL2:\.L.*]] +; SPARC64: nop +; SPARC64: and %g3, %o3, %g4 +; SPARC64: cmp %g2, %g4 +; SPARC64: bne %icc, [[LABEL1]] +; SPARC64: mov %g4, %g2 +; SPARC64: [[LABEL2]]: +; SPARC64: retl +; SPARC64: srl %g3, %o1, %o0 define i8 @test_cmpxchg_i8(i8 %a, i8* %ptr) { entry: %pair = cmpxchg i8* %ptr, i8 %a, i8 123 monotonic monotonic @@ -92,40 +145,72 @@ ret i8 %b } -; CHECK-LABEL: test_cmpxchg_i16 +; SPARC-LABEL: test_cmpxchg_i16 -; CHECK: and %o1, -4, %o2 -; CHECK: and %o1, 3, %o1 -; CHECK: xor %o1, 2, %o1 -; CHECK: sll %o1, 3, %o1 -; CHECK: sethi 63, %o3 -; CHECK: or %o3, 1023, %o4 -; CHECK: sll %o4, %o1, %o5 -; CHECK: xor %o5, -1, %o3 -; CHECK: and %o0, %o4, %o4 -; CHECK: ld [%o2], %g2 -; CHECK: mov 123, %o0 -; CHECK: sll %o0, %o1, %o0 -; CHECK: sll %o4, %o1, %o4 -; CHECK: andn %g2, %o5, %g2 -; CHECK: mov %g0, %o5 -; CHECK: [[LABEL1:\.L.*]]: -; CHECK: or %g2, %o0, %g3 -; CHECK: or %g2, %o4, %g4 -; CHECK: cas [%o2], %g4, %g3 -; CHECK: cmp %g3, %g4 -; CHECK: mov %o5, %g4 -; CHECK: move %icc, 1, %g4 -; CHECK: cmp %g4, 0 -; CHECK: bne [[LABEL2:\.L.*]] -; CHECK: nop -; CHECK: and %g3, %o3, %g4 -; CHECK: cmp %g2, %g4 -; CHECK: bne [[LABEL1]] -; CHECK: mov %g4, %g2 -; CHECK: [[LABEL2]]: -; CHECK: retl -; CHECK: srl %g3, %o1, %o0 +; SPARC: and %o1, -4, %o2 +; SPARC: and %o1, 3, %o1 +; SPARC: xor %o1, 2, %o1 +; SPARC: sll %o1, 3, %o1 +; SPARC: sethi 63, %o3 +; SPARC: or %o3, 1023, %o4 +; SPARC: sll %o4, %o1, %o5 +; SPARC: xor %o5, -1, %o3 +; SPARC: and %o0, %o4, %o4 +; SPARC: ld [%o2], %g2 +; SPARC: mov 123, %o0 +; SPARC: sll %o0, %o1, %o0 +; SPARC: sll %o4, %o1, %o4 +; SPARC: andn %g2, %o5, %g2 +; SPARC: mov %g0, %o5 +; SPARC: [[LABEL1:\.L.*]]: +; SPARC: or %g2, %o0, %g3 +; SPARC: or %g2, %o4, %g4 +; SPARC: cas [%o2], %g4, %g3 +; SPARC: cmp %g3, %g4 +; SPARC: mov %o5, %g4 +; SPARC: move %icc, 1, %g4 +; SPARC: cmp %g4, 0 +; SPARC: bne %icc, [[LABEL2:\.L.*]] +; SPARC: nop +; SPARC: and %g3, %o3, %g4 +; SPARC: cmp %g2, %g4 +; SPARC: bne %icc, [[LABEL1]] +; SPARC: mov %g4, %g2 +; SPARC: [[LABEL2]]: +; SPARC: retl +; SPARC: srl %g3, %o1, %o0 +; SPARC64: and %o1, -4, %o2 +; SPARC64: and %o1, 3, %o1 +; SPARC64: xor %o1, 2, %o1 +; SPARC64: sll %o1, 3, %o1 +; SPARC64: sethi 63, %o3 +; SPARC64: or %o3, 1023, %o4 +; SPARC64: sll %o4, %o1, %o5 +; SPARC64: xor %o5, -1, %o3 +; SPARC64: and %o0, %o4, %o4 +; SPARC64: ld [%o2], %g2 +; SPARC64: mov 123, %o0 +; SPARC64: sll %o0, %o1, %o0 +; SPARC64: sll %o4, %o1, %o4 +; SPARC64: andn %g2, %o5, %g2 +; SPARC64: mov %g0, %o5 +; SPARC64: [[LABEL1:\.L.*]]: +; SPARC64: or %g2, %o0, %g3 +; SPARC64: or %g2, %o4, %g4 +; SPARC64: cas [%o2], %g4, %g3 +; SPARC64: cmp %g3, %g4 +; SPARC64: mov %o5, %g4 +; SPARC64: move %icc, 1, %g4 +; SPARC64: cmp %g4, 0 +; SPARC64: bne %icc, [[LABEL2:\.L.*]] +; SPARC64: nop +; SPARC64: and %g3, %o3, %g4 +; SPARC64: cmp %g2, %g4 +; SPARC64: bne %icc, [[LABEL1]] +; SPARC64: mov %g4, %g2 +; SPARC64: [[LABEL2]]: +; SPARC64: retl +; SPARC64: srl %g3, %o1, %o0 define i16 @test_cmpxchg_i16(i16 %a, i16* %ptr) { entry: %pair = cmpxchg i16* %ptr, i16 %a, i16 123 monotonic monotonic @@ -133,10 +218,12 @@ ret i16 %b } -; CHECK-LABEL: test_cmpxchg_i32 -; CHECK: mov 123, [[R:%[gilo][0-7]]] -; CHECK: cas [%o1], %o0, [[R]] - +; SPARC-LABEL: test_cmpxchg_i32 +; SPARC: mov 123, [[R:%[gilo][0-7]]] +; SPARC: cas [%o1], %o0, [[R]] +; SPARC64-LABEL: test_cmpxchg_i32 +; SPARC64: mov 123, [[R:%[gilo][0-7]]] +; SPARC64: cas [%o1], %o0, [[R]] define i32 @test_cmpxchg_i32(i32 %a, i32* %ptr) { entry: %pair = cmpxchg i32* %ptr, i32 %a, i32 123 monotonic monotonic @@ -144,114 +231,162 @@ ret i32 %b } -; CHECK-LABEL: test_swap_i8 -; CHECK: mov 42, [[R:%[gilo][0-7]]] -; CHECK: cas - +; SPARC-LABEL: test_swap_i8 +; SPARC: mov 42, [[R:%[gilo][0-7]]] +; SPARC: cas +; SPARC64-LABEL: test_swap_i8 +; SPARC64: mov 42, [[R:%[gilo][0-7]]] +; SPARC64: cas define i8 @test_swap_i8(i8 %a, i8* %ptr) { entry: %b = atomicrmw xchg i8* %ptr, i8 42 monotonic ret i8 %b } -; CHECK-LABEL: test_swap_i16 -; CHECK: mov 42, [[R:%[gilo][0-7]]] -; CHECK: cas - +; SPARC-LABEL: test_swap_i16 +; SPARC: mov 42, [[R:%[gilo][0-7]]] +; SPARC: cas +; SPARC64-LABEL: test_swap_i16 +; SPARC64: mov 42, [[R:%[gilo][0-7]]] +; SPARC64: cas define i16 @test_swap_i16(i16 %a, i16* %ptr) { entry: %b = atomicrmw xchg i16* %ptr, i16 42 monotonic ret i16 %b } -; CHECK-LABEL: test_swap_i32 -; CHECK: mov 42, [[R:%[gilo][0-7]]] -; CHECK: swap [%o1], [[R]] - +; SPARC-LABEL: test_swap_i32 +; SPARC: mov 42, [[R:%[gilo][0-7]]] +; SPARC: swap [%o1], [[R]] +; SPARC64-LABEL: test_swap_i32 +; SPARC64: mov 42, [[R:%[gilo][0-7]]] +; SPARC64: swap [%o1], [[R]] define i32 @test_swap_i32(i32 %a, i32* %ptr) { entry: %b = atomicrmw xchg i32* %ptr, i32 42 monotonic ret i32 %b } -; CHECK-LABEL: test_load_sub_i8 -; CHECK: membar -; CHECK: .L{{.*}}: -; CHECK: sub -; CHECK: cas [{{%[gilo][0-7]}}] -; CHECK: membar +; SPARC-LABEL: test_load_sub_i8 +; SPARC: membar +; SPARC: .L{{.*}}: +; SPARC: sub +; SPARC: cas [{{%[gilo][0-7]}}] +; SPARC: membar +; SPARC64-LABEL: test_load_sub_i8 +; SPARC64: membar +; SPARC64: .L{{.*}}: +; SPARC64: sub +; SPARC64: cas [{{%[gilo][0-7]}}] +; SPARC64: membar define zeroext i8 @test_load_sub_i8(i8* %p, i8 zeroext %v) { entry: %0 = atomicrmw sub i8* %p, i8 %v seq_cst ret i8 %0 } -; CHECK-LABEL: test_load_sub_i16 -; CHECK: membar -; CHECK: .L{{.*}}: -; CHECK: sub -; CHECK: cas [{{%[gilo][0-7]}}] -; CHECK: membar +; SPARC-LABEL: test_load_sub_i16 +; SPARC: membar +; SPARC: .L{{.*}}: +; SPARC: sub +; SPARC: cas [{{%[gilo][0-7]}}] +; SPARC: membar +; SPARC64-LABEL: test_load_sub_i16 +; SPARC64: membar +; SPARC64: .L{{.*}}: +; SPARC64: sub +; SPARC64: cas [{{%[gilo][0-7]}}] +; SPARC64: membar define zeroext i16 @test_load_sub_i16(i16* %p, i16 zeroext %v) { entry: %0 = atomicrmw sub i16* %p, i16 %v seq_cst ret i16 %0 } -; CHECK-LABEL: test_load_add_i32 -; CHECK: membar -; CHECK: mov %g0 -; CHECK: mov [[U:%[gilo][0-7]]], [[V:%[gilo][0-7]]] -; CHECK: add [[U:%[gilo][0-7]]], %o1, [[V2:%[gilo][0-7]]] -; CHECK: cas [%o0], [[V]], [[V2]] -; CHECK: membar +; SPARC-LABEL: test_load_add_i32 +; SPARC: membar +; SPARC: mov %g0 +; SPARC: mov [[U:%[gilo][0-7]]], [[V:%[gilo][0-7]]] +; SPARC: add [[U:%[gilo][0-7]]], %o1, [[V2:%[gilo][0-7]]] +; SPARC: cas [%o0], [[V]], [[V2]] +; SPARC: membar +; SPARC64-LABEL: test_load_add_i32 +; SPARC64: membar +; SPARC64: mov %g0 +; SPARC64: mov [[U:%[gilo][0-7]]], [[V:%[gilo][0-7]]] +; SPARC64: add [[U:%[gilo][0-7]]], %o1, [[V2:%[gilo][0-7]]] +; SPARC64: cas [%o0], [[V]], [[V2]] +; SPARC64: membar define zeroext i32 @test_load_add_i32(i32* %p, i32 zeroext %v) { entry: %0 = atomicrmw add i32* %p, i32 %v seq_cst ret i32 %0 } -; CHECK-LABEL: test_load_xor_32 -; CHECK: membar -; CHECK: xor -; CHECK: cas [%o0] -; CHECK: membar +; SPARC-LABEL: test_load_xor_32 +; SPARC: membar +; SPARC: xor +; SPARC: cas [%o0] +; SPARC: membar +; SPARC64-LABEL: test_load_xor_32 +; SPARC64: membar +; SPARC64: xor +; SPARC64: cas [%o0] +; SPARC64: membar define zeroext i32 @test_load_xor_32(i32* %p, i32 zeroext %v) { entry: %0 = atomicrmw xor i32* %p, i32 %v seq_cst ret i32 %0 } -; CHECK-LABEL: test_load_and_32 -; CHECK: membar -; CHECK: and -; CHECK-NOT: xor -; CHECK: cas [%o0] -; CHECK: membar +; SPARC-LABEL: test_load_and_32 +; SPARC: membar +; SPARC: and +; SPARC-NOT: xor +; SPARC: cas [%o0] +; SPARC: membar +; SPARC64-LABEL: test_load_and_32 +; SPARC64: membar +; SPARC64: and +; SPARC64-NOT: xor +; SPARC64: cas [%o0] +; SPARC64: membar define zeroext i32 @test_load_and_32(i32* %p, i32 zeroext %v) { entry: %0 = atomicrmw and i32* %p, i32 %v seq_cst ret i32 %0 } -; CHECK-LABEL: test_load_nand_32 -; CHECK: membar -; CHECK: and -; CHECK: xor -; CHECK: cas [%o0] -; CHECK: membar +; SPARC-LABEL: test_load_nand_32 +; SPARC: membar +; SPARC: and +; SPARC: xor +; SPARC: cas [%o0] +; SPARC: membar +; SPARC64-LABEL: test_load_nand_32 +; SPARC64: membar +; SPARC64: and +; SPARC64: xor +; SPARC64: cas [%o0] +; SPARC64: membar define zeroext i32 @test_load_nand_32(i32* %p, i32 zeroext %v) { entry: %0 = atomicrmw nand i32* %p, i32 %v seq_cst ret i32 %0 } -; CHECK-LABEL: test_load_umin_32 -; CHECK: membar -; CHECK: cmp -; CHECK: movleu %icc -; CHECK: cas [%o0] -; CHECK: membar +; SPARC-LABEL: test_load_umin_32 +; SPARC: membar +; SPARC: cmp +; SPARC: movleu %icc +; SPARC: cas [%o0] +; SPARC: membar +; SPARC64-LABEL: test_load_umin_32 +; SPARC64: membar +; SPARC64: cmp +; SPARC64: movleu %icc +; SPARC64: cas [%o0] +; SPARC64: membar define zeroext i32 @test_load_umin_32(i32* %p, i32 zeroext %v) { entry: %0 = atomicrmw umin i32* %p, i32 %v seq_cst diff --git a/llvm/test/CodeGen/SPARC/branches-v9.ll b/llvm/test/CodeGen/SPARC/branches-v9.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/SPARC/branches-v9.ll @@ -0,0 +1,96 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=sparcv9 -disable-sparc-leaf-proc | FileCheck %s + +;; 1. When emitting code for v9, branches should always explicitly specify +;; %icc or %xcc. +;; 2. There should never be a `ba` that jumps into two instructions immediately +;; following it. + +define void @i(i32 signext %sel) { +; CHECK-LABEL: i: +; CHECK: .cfi_startproc +; CHECK-NEXT: ! %bb.0: ! %entry +; CHECK-NEXT: save %sp, -176, %sp +; CHECK-NEXT: .cfi_def_cfa_register %fp +; CHECK-NEXT: .cfi_window_save +; CHECK-NEXT: .cfi_register %o7, %i7 +; CHECK-NEXT: cmp %i0, 0 +; CHECK-NEXT: be %icc, .LBB0_2 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.1: ! %fbb +; CHECK-NEXT: call f2 +; CHECK-NEXT: nop +; CHECK-NEXT: ba %icc, .LBB0_3 +; CHECK-NEXT: nop +; CHECK-NEXT: .LBB0_2: ! %tbb +; CHECK-NEXT: call f1 +; CHECK-NEXT: nop +; CHECK-NEXT: .LBB0_3: ! %end +; CHECK-NEXT: call f3 +; CHECK-NEXT: nop +; CHECK-NEXT: ret +; CHECK-NEXT: restore +entry: + %cond = icmp eq i32 %sel, 0 + br i1 %cond, label %tbb, label %fbb + +fbb: + call void @f2() + br label %end + +tbb: + call void @f1() + br label %end + +end: + call void @f3() + ret void +} + +define void @l(i64 %sel) { +; CHECK-LABEL: l: +; CHECK: .cfi_startproc +; CHECK-NEXT: ! %bb.0: ! %entry +; CHECK-NEXT: save %sp, -176, %sp +; CHECK-NEXT: .cfi_def_cfa_register %fp +; CHECK-NEXT: .cfi_window_save +; CHECK-NEXT: .cfi_register %o7, %i7 +; CHECK-NEXT: cmp %i0, 0 +; CHECK-NEXT: be %xcc, .LBB1_2 +; CHECK-NEXT: nop +; CHECK-NEXT: ! %bb.1: ! %fbb +; CHECK-NEXT: call f2 +; CHECK-NEXT: nop +; CHECK-NEXT: ba %icc, .LBB1_3 +; CHECK-NEXT: nop +; CHECK-NEXT: .LBB1_2: ! %tbb +; CHECK-NEXT: call f1 +; CHECK-NEXT: nop +; CHECK-NEXT: .LBB1_3: ! %end +; CHECK-NEXT: call f3 +; CHECK-NEXT: nop +; CHECK-NEXT: ret +; CHECK-NEXT: restore +entry: + %cond = icmp eq i64 %sel, 0 + br i1 %cond, label %tbb, label %fbb + +fbb: + call void @f2() + br label %end + +tbb: + call void @f1() + br label %end + +end: + call void @f3() + ret void +} + +declare void @f1(...) + +declare void @f2(...) + +declare void @f3(...) + diff --git a/llvm/test/CodeGen/SPARC/hard-quad-float.ll b/llvm/test/CodeGen/SPARC/hard-quad-float.ll --- a/llvm/test/CodeGen/SPARC/hard-quad-float.ll +++ b/llvm/test/CodeGen/SPARC/hard-quad-float.ll @@ -8,7 +8,7 @@ ; SPARC64-NEXT: cmp %o0, 0 ; SPARC64-NEXT: fmovd %f8, %f0 ; SPARC64-NEXT: fmovd %f10, %f2 -; SPARC64-NEXT: be .LBB0_2 +; SPARC64-NEXT: be %icc, .LBB0_2 ; SPARC64-NEXT: nop ; SPARC64-NEXT: ! %bb.1: ; SPARC64-NEXT: fmovd %f4, %f0 diff --git a/llvm/test/CodeGen/SPARC/missinglabel.ll b/llvm/test/CodeGen/SPARC/missinglabel.ll --- a/llvm/test/CodeGen/SPARC/missinglabel.ll +++ b/llvm/test/CodeGen/SPARC/missinglabel.ll @@ -11,13 +11,11 @@ ; CHECK-NEXT: cmp %o0, 0 ; CHECK-NEXT: be %xcc, .LBB0_2 ; CHECK-NEXT: nop -; CHECK-NEXT: ba .LBB0_1 -; CHECK-NEXT: nop -; CHECK-NEXT: .LBB0_1: ! %cond.false +; CHECK-NEXT: ! %bb.1: ! %cond.false ; CHECK-NEXT: .LBB0_2: ! %targetblock ; CHECK-NEXT: mov %g0, %o0 ; CHECK-NEXT: cmp %o0, 0 -; CHECK-NEXT: bne .LBB0_4 +; CHECK-NEXT: bne %icc, .LBB0_4 ; CHECK-NEXT: nop ; CHECK-NEXT: ! %bb.3: ! %cond.false.i83 ; CHECK-NEXT: .LBB0_4: ! %exit.i85