[llvm] [Xtensa] Implement lowering SELECT_CC, SETCC. (PR #97017)
Andrei Safronov via llvm-commits
llvm-commits at lists.llvm.org
Fri Jun 28 00:27:07 PDT 2024
https://github.com/andreisfr created https://github.com/llvm/llvm-project/pull/97017
None
>From d37939680d08589fcdbbf9277a17ac16e0ff7dc2 Mon Sep 17 00:00:00 2001
From: Andrei Safronov <safronov at espressif.com>
Date: Fri, 28 Jun 2024 09:48:48 +0300
Subject: [PATCH] [Xtensa] Implement lowering SELECT_CC, SETCC.
---
llvm/lib/Target/Xtensa/XtensaISelLowering.cpp | 186 ++++++++++++++
llvm/lib/Target/Xtensa/XtensaISelLowering.h | 28 ++-
llvm/lib/Target/Xtensa/XtensaInstrInfo.td | 32 +++
llvm/lib/Target/Xtensa/XtensaOperators.td | 9 +
llvm/test/CodeGen/Xtensa/select-cc.ll | 125 ++++++++++
llvm/test/CodeGen/Xtensa/setcc.ll | 232 ++++++++++++++++++
llvm/utils/UpdateTestChecks/asm.py | 8 +
7 files changed, 619 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/Xtensa/select-cc.ll
create mode 100644 llvm/test/CodeGen/Xtensa/setcc.ll
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
index 6509793012504..8f19ae1b8e672 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.cpp
@@ -90,6 +90,26 @@ XtensaTargetLowering::XtensaTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::BR_CC, MVT::i64, Expand);
setOperationAction(ISD::BR_CC, MVT::f32, Expand);
+ // Used by legalize types to correctly generate the setcc result.
+ // AddPromotedToType(ISD::SETCC, MVT::i1, MVT::i32);
+ setOperationPromotedToType(ISD::SETCC, MVT::i1, MVT::i32);
+ setOperationPromotedToType(ISD::BR_CC, MVT::i1, MVT::i32);
+
+ setOperationAction(ISD::BR_CC, MVT::i32, Legal);
+ setOperationAction(ISD::BR_CC, MVT::i64, Expand);
+
+ setOperationAction(ISD::SELECT, MVT::i32, Expand);
+ setOperationAction(ISD::SELECT, MVT::i64, Expand);
+
+ setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::i64, Expand);
+
+ setOperationAction(ISD::SETCC, MVT::i32, Custom);
+ setOperationAction(ISD::SETCC, MVT::i64, Expand);
+
+ // make BRCOND legal, its actually only legal for a subset of conds
+ setOperationAction(ISD::BRCOND, MVT::Other, Legal);
+
// Implement custom stack allocations
setOperationAction(ISD::DYNAMIC_STACKALLOC, PtrVT, Custom);
// Implement custom stack save and restore
@@ -514,6 +534,38 @@ XtensaTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
return DAG.getNode(XtensaISD::RET, DL, MVT::Other, RetOps);
}
+SDValue XtensaTargetLowering::LowerSELECT_CC(SDValue Op,
+ SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ EVT Ty = Op.getOperand(0).getValueType();
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ SDValue TrueValue = Op.getOperand(2);
+ SDValue FalseValue = Op.getOperand(3);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op->getOperand(4))->get();
+ SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32);
+
+ // Wrap select nodes
+ return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueValue,
+ FalseValue, TargetCC);
+}
+
+SDValue XtensaTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ EVT Ty = Op.getOperand(0).getValueType();
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
+ SDValue TargetCC = DAG.getConstant(CC, DL, MVT::i32);
+
+ // Expand to target SELECT_CC
+ SDValue TrueValue = DAG.getConstant(1, DL, Op.getValueType());
+ SDValue FalseValue = DAG.getConstant(0, DL, Op.getValueType());
+
+ return DAG.getNode(XtensaISD::SELECT_CC, DL, Ty, LHS, RHS, TrueValue,
+ FalseValue, TargetCC);
+}
+
SDValue XtensaTargetLowering::LowerImmediate(SDValue Op,
SelectionDAG &DAG) const {
const ConstantSDNode *CN = cast<ConstantSDNode>(Op);
@@ -676,6 +728,10 @@ SDValue XtensaTargetLowering::LowerOperation(SDValue Op,
return LowerJumpTable(Op, DAG);
case ISD::ConstantPool:
return LowerConstantPool(cast<ConstantPoolSDNode>(Op), DAG);
+ case ISD::SETCC:
+ return LowerSETCC(Op, DAG);
+ case ISD::SELECT_CC:
+ return LowerSELECT_CC(Op, DAG);
case ISD::STACKSAVE:
return LowerSTACKSAVE(Op, DAG);
case ISD::STACKRESTORE:
@@ -697,6 +753,136 @@ const char *XtensaTargetLowering::getTargetNodeName(unsigned Opcode) const {
return "XtensaISD::PCREL_WRAPPER";
case XtensaISD::RET:
return "XtensaISD::RET";
+ case XtensaISD::SELECT:
+ return "XtensaISD::SELECT";
+ case XtensaISD::SELECT_CC:
+ return "XtensaISD::SELECT_CC";
}
return nullptr;
}
+
+//===----------------------------------------------------------------------===//
+// Custom insertion
+//===----------------------------------------------------------------------===//
+
+static int GetBranchKind(int Cond, bool &BrInv) {
+ switch (Cond) {
+ case ISD::SETEQ:
+ case ISD::SETOEQ:
+ case ISD::SETUEQ:
+ return Xtensa::BEQ;
+ case ISD::SETNE:
+ case ISD::SETONE:
+ case ISD::SETUNE:
+ return Xtensa::BNE;
+ case ISD::SETLT:
+ case ISD::SETOLT:
+ return Xtensa::BLT;
+ case ISD::SETLE:
+ case ISD::SETOLE:
+ BrInv = true;
+ return Xtensa::BGE;
+ case ISD::SETGT:
+ case ISD::SETOGT:
+ BrInv = true;
+ return Xtensa::BLT;
+ case ISD::SETGE:
+ case ISD::SETOGE:
+ return Xtensa::BGE;
+ case ISD::SETULT:
+ return Xtensa::BLTU;
+ case ISD::SETULE:
+ BrInv = true;
+ return Xtensa::BGEU;
+ case ISD::SETUGT:
+ BrInv = true;
+ return Xtensa::BLTU;
+ case ISD::SETUGE:
+ return Xtensa::BGEU;
+ default:
+ return -1;
+ }
+}
+
+MachineBasicBlock *
+XtensaTargetLowering::emitSelectCC(MachineInstr &MI,
+ MachineBasicBlock *MBB) const {
+ const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
+ DebugLoc DL = MI.getDebugLoc();
+
+ MachineOperand &LHS = MI.getOperand(1);
+ MachineOperand &RHS = MI.getOperand(2);
+ MachineOperand &TrueValue = MI.getOperand(3);
+ MachineOperand &FalseValue = MI.getOperand(4);
+ MachineOperand &Cond = MI.getOperand(5);
+
+ // To "insert" a SELECT_CC instruction, we actually have to insert
+ // CopyMBB and SinkMBB blocks and add branch to MBB. We build phi
+ // operation in SinkMBB like phi (TrueVakue,FalseValue), where TrueValue
+ // is passed from MMB and FalseValue is passed from CopyMBB.
+ // MBB
+ // | \
+ // | CopyMBB
+ // | /
+ // SinkMBB
+ // The incoming instruction knows the
+ // destination vreg to set, the condition code register to branch on, the
+ // true/false values to select between, and a branch opcode to use.
+ const BasicBlock *LLVM_BB = MBB->getBasicBlock();
+ MachineFunction::iterator It = ++MBB->getIterator();
+
+ MachineFunction *F = MBB->getParent();
+ MachineBasicBlock *CopyMBB = F->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *SinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
+
+ F->insert(It, CopyMBB);
+ F->insert(It, SinkMBB);
+
+ // Transfer the remainder of MBB and its successor edges to SinkMBB.
+ SinkMBB->splice(SinkMBB->begin(), MBB,
+ std::next(MachineBasicBlock::iterator(MI)), MBB->end());
+ SinkMBB->transferSuccessorsAndUpdatePHIs(MBB);
+
+ MBB->addSuccessor(CopyMBB);
+ MBB->addSuccessor(SinkMBB);
+
+ bool BrInv = false;
+ int BrKind = GetBranchKind(Cond.getImm(), BrInv);
+ if (BrInv) {
+ BuildMI(MBB, DL, TII.get(BrKind))
+ .addReg(RHS.getReg())
+ .addReg(LHS.getReg())
+ .addMBB(SinkMBB);
+ } else {
+ BuildMI(MBB, DL, TII.get(BrKind))
+ .addReg(LHS.getReg())
+ .addReg(RHS.getReg())
+ .addMBB(SinkMBB);
+ }
+
+ CopyMBB->addSuccessor(SinkMBB);
+
+ // SinkMBB:
+ // %Result = phi [ %FalseValue, CopyMBB ], [ %TrueValue, MBB ]
+ // ...
+
+ BuildMI(*SinkMBB, SinkMBB->begin(), DL, TII.get(Xtensa::PHI),
+ MI.getOperand(0).getReg())
+ .addReg(FalseValue.getReg())
+ .addMBB(CopyMBB)
+ .addReg(TrueValue.getReg())
+ .addMBB(MBB);
+
+ MI.eraseFromParent(); // The pseudo instruction is gone now.
+ return SinkMBB;
+}
+
+MachineBasicBlock *XtensaTargetLowering::EmitInstrWithCustomInserter(
+ MachineInstr &MI, MachineBasicBlock *MBB) const {
+ switch (MI.getOpcode()) {
+ case Xtensa::SELECT:
+ return emitSelectCC(MI, MBB);
+ default:
+ report_fatal_error("Unexpected instr type to insert");
+ }
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaISelLowering.h b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
index 23a0217daaa96..8a4491c38db5f 100644
--- a/llvm/lib/Target/Xtensa/XtensaISelLowering.h
+++ b/llvm/lib/Target/Xtensa/XtensaISelLowering.h
@@ -33,7 +33,14 @@ enum {
// Wraps a TargetGlobalAddress that should be loaded using PC-relative
// accesses. Operand 0 is the address.
PCREL_WRAPPER,
- RET
+ RET,
+
+ // Selects between operand 0 and operand 1. Operand 2 is the
+ // mask of condition-code values for which operand 0 should be
+ // chosen over operand 1; it has the same form as BR_CCMASK.
+ // Operand 3 is the flag operand.
+ SELECT,
+ SELECT_CC
};
}
@@ -44,6 +51,13 @@ class XtensaTargetLowering : public TargetLowering {
explicit XtensaTargetLowering(const TargetMachine &TM,
const XtensaSubtarget &STI);
+ EVT getSetCCResultType(const DataLayout &, LLVMContext &,
+ EVT VT) const override {
+ if (!VT.isVector())
+ return MVT::i32;
+ return VT.changeVectorElementTypeToInteger();
+ }
+
bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
const char *getTargetNodeName(unsigned Opcode) const override;
@@ -71,6 +85,10 @@ class XtensaTargetLowering : public TargetLowering {
const XtensaSubtarget &getSubtarget() const { return Subtarget; }
+ MachineBasicBlock *
+ EmitInstrWithCustomInserter(MachineInstr &MI,
+ MachineBasicBlock *BB) const override;
+
private:
const XtensaSubtarget &Subtarget;
@@ -86,6 +104,10 @@ class XtensaTargetLowering : public TargetLowering {
SDValue LowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const;
+ SDValue LowerSETCC(SDValue Op, SelectionDAG &DAG) const;
+
+ SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
+
SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerSTACKSAVE(SDValue Op, SelectionDAG &DAG) const;
@@ -95,6 +117,10 @@ class XtensaTargetLowering : public TargetLowering {
SDValue getAddrPCRel(SDValue Op, SelectionDAG &DAG) const;
CCAssignFn *CCAssignFnForCall(CallingConv::ID CC, bool IsVarArg) const;
+
+ // Implement EmitInstrWithCustomInserter for individual operation types.
+ MachineBasicBlock *emitSelectCC(MachineInstr &MI,
+ MachineBasicBlock *BB) const;
};
} // end namespace llvm
diff --git a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
index f68d20dcdd54a..9e3a35808d0b6 100644
--- a/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
+++ b/llvm/lib/Target/Xtensa/XtensaInstrInfo.td
@@ -425,6 +425,29 @@ def : Pat<(brcc SETLE, AR:$s, AR:$t, bb:$target),
def : Pat<(brcc SETULE, AR:$s, AR:$t, bb:$target),
(BGEU AR:$t, AR:$s, bb:$target)>;
+def : Pat<(brcond (i32 (seteq AR:$s, AR:$t)), bb:$target),
+ (BEQ AR:$s, AR:$t, bb:$target)>;
+def : Pat<(brcond (i32 (setne AR:$s, AR:$t)), bb:$target),
+ (BNE AR:$s, AR:$t, bb:$target)>;
+def : Pat<(brcond (i32 (setge AR:$s, AR:$t)), bb:$target),
+ (BGE AR:$s, AR:$t, bb:$target)>;
+def : Pat<(brcond (i32 (setle AR:$s, AR:$t)), bb:$target),
+ (BLT AR:$s, AR:$t, bb:$target)>;
+def : Pat<(brcond (i32 (setuge AR:$s, AR:$t)), bb:$target),
+ (BGEU AR:$s, AR:$t, bb:$target)>;
+def : Pat<(brcond (i32 (setult AR:$s, AR:$t)), bb:$target),
+ (BLTU AR:$s, AR:$t, bb:$target)>;
+def : Pat<(brcond (i32 (setgt AR:$s, AR:$t)), bb:$target),
+ (BLT AR:$t, AR:$s, bb:$target)>;
+def : Pat<(brcond (i32 (setugt AR:$s, AR:$t)), bb:$target),
+ (BLTU AR:$t, AR:$s, bb:$target)>;
+def : Pat<(brcond (i32 (setle AR:$s, AR:$t)), bb:$target),
+ (BGE AR:$t, AR:$s, bb:$target)>;
+def : Pat<(brcond (i32 (setule AR:$s, AR:$t)), bb:$target),
+ (BGEU AR:$t, AR:$s, bb:$target)>;
+
+def : Pat<(brcond AR:$s, bb:$target), (BNEZ AR:$s, bb:$target)>;
+
//===----------------------------------------------------------------------===//
// Call and jump instructions
//===----------------------------------------------------------------------===//
@@ -574,3 +597,12 @@ let Defs = [SP], Uses = [SP] in {
"#ADJCALLSTACKUP",
[(Xtensa_callseq_end timm:$amt1, timm:$amt2)]>;
}
+
+//===----------------------------------------------------------------------===//
+// Generic select instruction
+//===----------------------------------------------------------------------===//
+let usesCustomInserter = 1 in {
+ def SELECT : Pseudo<(outs AR:$dst), (ins AR:$lhs, AR:$rhs, AR:$t, AR:$f, i32imm:$cond),
+ "!select $dst, $lhs, $rhs, $t, $f, $cond",
+ [(set AR:$dst, (Xtensa_select_cc AR:$lhs, AR:$rhs, AR:$t, AR:$f, imm:$cond))]>;
+}
diff --git a/llvm/lib/Target/Xtensa/XtensaOperators.td b/llvm/lib/Target/Xtensa/XtensaOperators.td
index 88d3c9dfe7fd8..aab2d2d2bbe79 100644
--- a/llvm/lib/Target/Xtensa/XtensaOperators.td
+++ b/llvm/lib/Target/Xtensa/XtensaOperators.td
@@ -19,6 +19,11 @@ def SDT_XtensaWrapPtr : SDTypeProfile<1, 1,
def SDT_XtensaBrJT : SDTypeProfile<0, 2,
[SDTCisPtrTy<0>, SDTCisVT<1, i32>]>;
+
+def SDT_XtensaSelectCC : SDTypeProfile<1, 5,
+ [SDTCisSameAs<0, 1>,
+ SDTCisSameAs<2, 3>,
+ SDTCisVT<5, i32>]>;
//===----------------------------------------------------------------------===//
// Node definitions
//===----------------------------------------------------------------------===//
@@ -38,3 +43,7 @@ def Xtensa_callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_XtensaCallSeqEnd,
SDNPOutGlue]>;
def Xtensa_brjt: SDNode<"XtensaISD::BR_JT", SDT_XtensaBrJT, [SDNPHasChain]>;
+
+def Xtensa_select : SDNode<"XtensaISD::SELECT", SDTSelect>;
+def Xtensa_select_cc: SDNode<"XtensaISD::SELECT_CC", SDT_XtensaSelectCC,
+ [SDNPInGlue]>;
diff --git a/llvm/test/CodeGen/Xtensa/select-cc.ll b/llvm/test/CodeGen/Xtensa/select-cc.ll
new file mode 100644
index 0000000000000..6073ee7cc2558
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/select-cc.ll
@@ -0,0 +1,125 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc -mtriple=xtensa -disable-block-placement -verify-machineinstrs < %s \
+; RUN: | FileCheck %s
+
+define signext i32 @foo(i32 signext %a, ptr %b) nounwind {
+; CHECK-LABEL: foo:
+; CHECK: l32i a8, a3, 0
+; CHECK-NEXT: beq a2, a8, .LBB0_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_2:
+; CHECK-NEXT: bne a2, a8, .LBB0_4
+; CHECK-NEXT: # %bb.3:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_4:
+; CHECK-NEXT: bltu a8, a2, .LBB0_6
+; CHECK-NEXT: # %bb.5:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_6:
+; CHECK-NEXT: bgeu a2, a8, .LBB0_8
+; CHECK-NEXT: # %bb.7:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_8:
+; CHECK-NEXT: bltu a2, a8, .LBB0_10
+; CHECK-NEXT: # %bb.9:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_10:
+; CHECK-NEXT: bgeu a8, a2, .LBB0_12
+; CHECK-NEXT: # %bb.11:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_12:
+; CHECK-NEXT: blt a8, a2, .LBB0_14
+; CHECK-NEXT: # %bb.13:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_14:
+; CHECK-NEXT: bge a2, a8, .LBB0_16
+; CHECK-NEXT: # %bb.15:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_16:
+; CHECK-NEXT: blt a2, a8, .LBB0_18
+; CHECK-NEXT: # %bb.17:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_18:
+; CHECK-NEXT: bge a8, a2, .LBB0_20
+; CHECK-NEXT: # %bb.19:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_20:
+; CHECK-NEXT: movi a9, 1
+; CHECK-NEXT: blt a8, a9, .LBB0_22
+; CHECK-NEXT: # %bb.21:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_22:
+; CHECK-NEXT: movi a9, -1
+; CHECK-NEXT: blt a9, a8, .LBB0_24
+; CHECK-NEXT: # %bb.23:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_24:
+; CHECK-NEXT: movi a9, 1024
+; CHECK-NEXT: blt a9, a8, .LBB0_26
+; CHECK-NEXT: # %bb.25:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_26:
+; CHECK-NEXT: movi a9, 2046
+; CHECK-NEXT: bltu a9, a8, .LBB0_28
+; CHECK-NEXT: # %bb.27:
+; CHECK-NEXT: or a2, a8, a8
+; CHECK-NEXT: .LBB0_28:
+; CHECK-NEXT: ret
+ %val1 = load i32, ptr %b
+ %tst1 = icmp eq i32 %a, %val1
+ %val2 = select i1 %tst1, i32 %a, i32 %val1
+
+ %val3 = load i32, ptr %b
+ %tst2 = icmp ne i32 %val2, %val3
+ %val4 = select i1 %tst2, i32 %val2, i32 %val3
+
+ %val5 = load i32, ptr %b
+ %tst3 = icmp ugt i32 %val4, %val5
+ %val6 = select i1 %tst3, i32 %val4, i32 %val5
+
+ %val7 = load i32, ptr %b
+ %tst4 = icmp uge i32 %val6, %val7
+ %val8 = select i1 %tst4, i32 %val6, i32 %val7
+
+ %val9 = load i32, ptr %b
+ %tst5 = icmp ult i32 %val8, %val9
+ %val10 = select i1 %tst5, i32 %val8, i32 %val9
+
+ %val11 = load i32, ptr %b
+ %tst6 = icmp ule i32 %val10, %val11
+ %val12 = select i1 %tst6, i32 %val10, i32 %val11
+
+ %val13 = load i32, ptr %b
+ %tst7 = icmp sgt i32 %val12, %val13
+ %val14 = select i1 %tst7, i32 %val12, i32 %val13
+
+ %val15 = load i32, ptr %b
+ %tst8 = icmp sge i32 %val14, %val15
+ %val16 = select i1 %tst8, i32 %val14, i32 %val15
+
+ %val17 = load i32, ptr %b
+ %tst9 = icmp slt i32 %val16, %val17
+ %val18 = select i1 %tst9, i32 %val16, i32 %val17
+
+ %val19 = load i32, ptr %b
+ %tst10 = icmp sle i32 %val18, %val19
+ %val20 = select i1 %tst10, i32 %val18, i32 %val19
+
+ %val21 = load i32, ptr %b
+ %tst11 = icmp slt i32 %val21, 1
+ %val22 = select i1 %tst11, i32 %val20, i32 %val21
+
+ %val23 = load i32, ptr %b
+ %tst12 = icmp sgt i32 %val21, -1
+ %val24 = select i1 %tst12, i32 %val22, i32 %val23
+
+ %val25 = load i32, ptr %b
+ %tst13 = icmp sgt i32 %val25, 1024
+ %val26 = select i1 %tst13, i32 %val24, i32 %val25
+
+ %val27 = load i32, ptr %b
+ %tst14 = icmp ugt i32 %val21, 2046
+ %val28 = select i1 %tst14, i32 %val26, i32 %val27
+ ret i32 %val28
+}
diff --git a/llvm/test/CodeGen/Xtensa/setcc.ll b/llvm/test/CodeGen/Xtensa/setcc.ll
new file mode 100644
index 0000000000000..a8557b2365a31
--- /dev/null
+++ b/llvm/test/CodeGen/Xtensa/setcc.ll
@@ -0,0 +1,232 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=xtensa-unkonwn-elf -O0 | FileCheck %s
+
+define i32 @f1(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f1:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: beq a2, a3, .LBB0_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB0_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp eq i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
+
+define i32 @f2(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f2:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: blt a2, a3, .LBB1_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB1_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp slt i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
+
+define i32 @f3(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f3:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: bge a3, a2, .LBB2_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB2_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp sle i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
+
+define i32 @f4(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f4:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: blt a3, a2, .LBB3_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB3_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp sgt i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
+
+define i32 @f5(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f5:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: bge a2, a3, .LBB4_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB4_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp sge i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
+
+define i32 @f6(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f6:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: bne a2, a3, .LBB5_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB5_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp ne i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
+
+define i32 @f7(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f7:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: bltu a2, a3, .LBB6_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB6_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp ult i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
+
+define i32 @f8(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f8:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: bgeu a3, a2, .LBB7_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB7_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp ule i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
+
+define i32 @f9(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f9:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: bltu a3, a2, .LBB8_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB8_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp ugt i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
+
+define i32 @f10(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: f10:
+; CHECK: addi a8, a1, -16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: movi a8, 0
+; CHECK-NEXT: s32i a8, a1, 0 # 4-byte Folded Spill
+; CHECK-NEXT: movi a8, 1
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: bgeu a2, a3, .LBB9_2
+; CHECK-NEXT: # %bb.1:
+; CHECK-NEXT: l32i a8, a1, 0 # 4-byte Folded Reload
+; CHECK-NEXT: s32i a8, a1, 4 # 4-byte Folded Spill
+; CHECK-NEXT: .LBB9_2:
+; CHECK-NEXT: l32i a2, a1, 4 # 4-byte Folded Reload
+; CHECK-NEXT: addi a8, a1, 16
+; CHECK-NEXT: or a1, a8, a8
+; CHECK-NEXT: ret
+
+ %cond = icmp uge i32 %a, %b
+ %res = zext i1 %cond to i32
+ ret i32 %res
+}
diff --git a/llvm/utils/UpdateTestChecks/asm.py b/llvm/utils/UpdateTestChecks/asm.py
index f150098eaaeef..3fa67e34e21d7 100644
--- a/llvm/utils/UpdateTestChecks/asm.py
+++ b/llvm/utils/UpdateTestChecks/asm.py
@@ -109,6 +109,13 @@ class string:
flags=(re.M | re.S),
)
+ASM_FUNCTION_XTENSA_RE = re.compile(
+ r'^_?(?P<func>[^.:]+):[ \t]*#+[ \t]*@"?(?P=func)"?\n# %bb.0:\n'
+ r'(?P<body>.*?)\n'
+ r'^\.Lfunc_end\d+:\n', # Match the end label
+ flags=(re.M | re.S)
+)
+
ASM_FUNCTION_PPC_RE = re.compile(
r"#[ \-\t]*Begin function (?P<func>[^.:]+)\n"
r".*?"
@@ -579,6 +586,7 @@ def get_run_handler(triple):
"nvptx": (scrub_asm_nvptx, ASM_FUNCTION_NVPTX_RE),
"loongarch32": (scrub_asm_loongarch, ASM_FUNCTION_LOONGARCH_RE),
"loongarch64": (scrub_asm_loongarch, ASM_FUNCTION_LOONGARCH_RE),
+ "xtensa": (scrub_asm_avr, ASM_FUNCTION_XTENSA_RE),
}
handler = None
best_prefix = ""
More information about the llvm-commits
mailing list