forked from OSchip/llvm-project
Add checkevent intrinsic to check if any resources owned by the current thread
can event. llvm-svn: 127741
This commit is contained in:
parent
ce0bc31469
commit
d4346f2388
|
@ -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<[],[],[]>;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue