summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/IntrinsicsXCore.td6
-rw-r--r--lib/Target/XCore/XCoreISelDAGToDAG.cpp182
-rw-r--r--lib/Target/XCore/XCoreInstrInfo.td7
-rw-r--r--test/CodeGen/XCore/events.ll20
4 files changed, 160 insertions, 55 deletions
diff --git a/include/llvm/IntrinsicsXCore.td b/include/llvm/IntrinsicsXCore.td
index 056ae04f91..48ff9ce507 100644
--- a/include/llvm/IntrinsicsXCore.td
+++ b/include/llvm/IntrinsicsXCore.td
@@ -56,5 +56,11 @@ let TargetPrefix = "xcore" in { // All intrinsics start with "llvm.xcore.".
// Intrinsics for events.
def int_xcore_waitevent : Intrinsic<[llvm_ptr_ty],[], [IntrReadMem]>;
+
+ // If any of the resources owned by the thread are ready this returns the
+ // vector of one of the ready resources. If no resources owned by the thread
+ // are ready then the operand passed to the intrinsic is returned.
+ def int_xcore_checkevent : Intrinsic<[llvm_ptr_ty],[llvm_ptr_ty]>;
+
def int_xcore_clre : Intrinsic<[],[],[]>;
}
diff --git a/lib/Target/XCore/XCoreISelDAGToDAG.cpp b/lib/Target/XCore/XCoreISelDAGToDAG.cpp
index 4d2ff81ad4..8ce93fd93a 100644
--- a/lib/Target/XCore/XCoreISelDAGToDAG.cpp
+++ b/lib/Target/XCore/XCoreISelDAGToDAG.cpp
@@ -49,7 +49,8 @@ namespace {
Subtarget(*TM.getSubtargetImpl()) { }
SDNode *Select(SDNode *N);
-
+ SDNode *SelectBRIND(SDNode *N);
+
/// getI32Imm - Return a target constant with the specified value, of type
/// i32.
inline SDValue getI32Imm(unsigned Imm) {
@@ -154,62 +155,133 @@ bool XCoreDAGToDAGISel::SelectADDRcpii(SDValue Addr, SDValue &Base,
SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
DebugLoc dl = N->getDebugLoc();
- EVT NVT = N->getValueType(0);
- if (NVT == MVT::i32) {
- switch (N->getOpcode()) {
- default: break;
- case ISD::Constant: {
- uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
- if (immMskBitp(N)) {
- // Transformation function: get the size of a mask
- // Look for the first non-zero bit
- SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val));
- return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
- MVT::i32, MskSize);
- }
- else if (!isUInt<16>(Val)) {
- SDValue CPIdx =
- CurDAG->getTargetConstantPool(ConstantInt::get(
- Type::getInt32Ty(*CurDAG->getContext()), Val),
- TLI.getPointerTy());
- return CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
- MVT::Other, CPIdx,
- CurDAG->getEntryNode());
- }
- break;
- }
- case XCoreISD::LADD: {
- SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
- N->getOperand(2) };
- return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
- Ops, 3);
- }
- case XCoreISD::LSUB: {
- SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
- N->getOperand(2) };
- return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
- Ops, 3);
+ switch (N->getOpcode()) {
+ default: break;
+ case ISD::Constant: {
+ uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
+ if (immMskBitp(N)) {
+ // Transformation function: get the size of a mask
+ // Look for the first non-zero bit
+ SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val));
+ return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
+ MVT::i32, MskSize);
}
- case XCoreISD::MACCU: {
- SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
- N->getOperand(2), N->getOperand(3) };
- return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
- Ops, 4);
- }
- case XCoreISD::MACCS: {
- SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
- N->getOperand(2), N->getOperand(3) };
- return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
- Ops, 4);
- }
- case XCoreISD::LMUL: {
- SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
- N->getOperand(2), N->getOperand(3) };
- return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
- Ops, 4);
- }
- // Other cases are autogenerated.
+ else if (!isUInt<16>(Val)) {
+ SDValue CPIdx =
+ CurDAG->getTargetConstantPool(ConstantInt::get(
+ Type::getInt32Ty(*CurDAG->getContext()), Val),
+ TLI.getPointerTy());
+ return CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
+ MVT::Other, CPIdx,
+ CurDAG->getEntryNode());
}
+ break;
+ }
+ case XCoreISD::LADD: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2) };
+ return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
+ Ops, 3);
+ }
+ case XCoreISD::LSUB: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2) };
+ return CurDAG->getMachineNode(XCore::LSUB_l5r, dl, MVT::i32, MVT::i32,
+ Ops, 3);
+ }
+ case XCoreISD::MACCU: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2), N->getOperand(3) };
+ return CurDAG->getMachineNode(XCore::MACCU_l4r, dl, MVT::i32, MVT::i32,
+ Ops, 4);
+ }
+ case XCoreISD::MACCS: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2), N->getOperand(3) };
+ return CurDAG->getMachineNode(XCore::MACCS_l4r, dl, MVT::i32, MVT::i32,
+ Ops, 4);
+ }
+ case XCoreISD::LMUL: {
+ SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
+ N->getOperand(2), N->getOperand(3) };
+ return CurDAG->getMachineNode(XCore::LMUL_l6r, dl, MVT::i32, MVT::i32,
+ Ops, 4);
+ }
+ case ISD::BRIND:
+ if (SDNode *ResNode = SelectBRIND(N))
+ return ResNode;
+ break;
+ // Other cases are autogenerated.
}
return SelectCode(N);
}
+
+/// Given a chain return a new chain where any appearance of Old is replaced
+/// by New. There must be at most one instruction between Old and Chain and
+/// this instruction must be a TokenFactor. Returns an empty SDValue if
+/// these conditions don't hold.
+static SDValue
+replaceInChain(SelectionDAG *CurDAG, SDValue Chain, SDValue Old, SDValue New)
+{
+ if (Chain == Old)
+ return New;
+ if (Chain->getOpcode() != ISD::TokenFactor)
+ return SDValue();
+ SmallVector<SDValue, 8> Ops;
+ bool found = false;
+ for (unsigned i = 0, e = Chain->getNumOperands(); i != e; ++i) {
+ if (Chain->getOperand(i) == Old) {
+ Ops.push_back(New);
+ found = true;
+ } else {
+ Ops.push_back(Chain->getOperand(i));
+ }
+ }
+ if (!found)
+ return SDValue();
+ return CurDAG->getNode(ISD::TokenFactor, Chain->getDebugLoc(), MVT::Other,
+ &Ops[0], Ops.size());
+}
+
+SDNode *XCoreDAGToDAGISel::SelectBRIND(SDNode *N) {
+ DebugLoc dl = N->getDebugLoc();
+ // (brind (int_xcore_checkevent (addr)))
+ SDValue Chain = N->getOperand(0);
+ SDValue Addr = N->getOperand(1);
+ if (Addr->getOpcode() != ISD::INTRINSIC_W_CHAIN)
+ return 0;
+ unsigned IntNo = cast<ConstantSDNode>(Addr->getOperand(1))->getZExtValue();
+ if (IntNo != Intrinsic::xcore_checkevent)
+ return 0;
+ SDValue nextAddr = Addr->getOperand(2);
+ SDValue CheckEventChainOut(Addr.getNode(), 1);
+ if (!CheckEventChainOut.use_empty()) {
+ // If the chain out of the checkevent intrinsic is an operand of the
+ // indirect branch or used in a TokenFactor which is the operand of the
+ // indirect branch then build a new chain which uses the chain coming into
+ // the checkevent intrinsic instead.
+ SDValue CheckEventChainIn = Addr->getOperand(0);
+ SDValue NewChain = replaceInChain(CurDAG, Chain, CheckEventChainOut,
+ CheckEventChainIn);
+ if (!NewChain.getNode())
+ return 0;
+ Chain = NewChain;
+ }
+ // Enable events on the thread using setsr 1 and then disable them immediately
+ // after with clrsr 1. If any resources owned by the thread are ready an event
+ // will be taken. If no resource is ready we branch to the address which was
+ // the operand to the checkevent intrinsic.
+ SDValue constOne = getI32Imm(1);
+ SDValue Glue =
+ SDValue(CurDAG->getMachineNode(XCore::SETSR_branch_u6, dl, MVT::Glue,
+ constOne, Chain), 0);
+ Glue =
+ SDValue(CurDAG->getMachineNode(XCore::CLRSR_branch_u6, dl, MVT::Glue,
+ constOne, Glue), 0);
+ if (nextAddr->getOpcode() == XCoreISD::PCRelativeWrapper &&
+ nextAddr->getOperand(0)->getOpcode() == ISD::TargetBlockAddress) {
+ return CurDAG->SelectNodeTo(N, XCore::BRFU_lu6, MVT::Other,
+ nextAddr->getOperand(0), Glue);
+ }
+ return CurDAG->SelectNodeTo(N, XCore::BAU_1r, MVT::Other, nextAddr, Glue);
+}
diff --git a/lib/Target/XCore/XCoreInstrInfo.td b/lib/Target/XCore/XCoreInstrInfo.td
index 59c902d434..c56792c7ee 100644
--- a/lib/Target/XCore/XCoreInstrInfo.td
+++ b/lib/Target/XCore/XCoreInstrInfo.td
@@ -692,6 +692,13 @@ defm SETSR : FU6_LU6_int<"setsr", int_xcore_setsr>;
defm CLRSR : FU6_LU6_int<"clrsr", int_xcore_clrsr>;
+// setsr may cause a branch if it is used to enable events. clrsr may
+// branch if it is executed while events are enabled.
+let isBranch=1, isIndirectBranch=1, isTerminator=1, isBarrier = 1 in {
+defm SETSR_branch : FU6_LU6_np<"setsr">;
+defm CLRSR_branch : FU6_LU6_np<"clrsr">;
+}
+
// U10
// TODO ldwcpl, blacp
diff --git a/test/CodeGen/XCore/events.ll b/test/CodeGen/XCore/events.ll
index 4fc2f26d1b..30a6ec3551 100644
--- a/test/CodeGen/XCore/events.ll
+++ b/test/CodeGen/XCore/events.ll
@@ -2,6 +2,7 @@
declare void @llvm.xcore.setv.p1i8(i8 addrspace(1)* %r, i8* %p)
declare i8* @llvm.xcore.waitevent()
+declare i8* @llvm.xcore.checkevent(i8*)
declare void @llvm.xcore.clre()
define i32 @f(i8 addrspace(1)* %r) nounwind {
@@ -22,3 +23,22 @@ ret:
%retval = phi i32 [1, %L1], [2, %L2]
ret i32 %retval
}
+
+define i32 @g(i8 addrspace(1)* %r) nounwind {
+; CHECK: g:
+entry:
+; CHECK: clre
+ call void @llvm.xcore.clre()
+ call void @llvm.xcore.setv.p1i8(i8 addrspace(1)* %r, i8* blockaddress(@f, %L1))
+ %goto_addr = call i8* @llvm.xcore.checkevent(i8 *blockaddress(@f, %L2))
+; CHECK: setsr 1
+; CHECK: clrsr 1
+ indirectbr i8* %goto_addr, [label %L1, label %L2]
+L1:
+ br label %ret
+L2:
+ br label %ret
+ret:
+ %retval = phi i32 [1, %L1], [2, %L2]
+ ret i32 %retval
+}