Add checkevent intrinsic to check if any resources owned by the current thread

can event.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@127741 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Osborne 2011-03-16 18:34:00 +00:00
parent bfc4c983a6
commit bb057453db
4 changed files with 160 additions and 55 deletions

View File

@ -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<[],[],[]>;
}

View File

@ -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;
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::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);
}
// 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);
}

View File

@ -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

View File

@ -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
}