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.
|
// Intrinsics for events.
|
||||||
def int_xcore_waitevent : Intrinsic<[llvm_ptr_ty],[], [IntrReadMem]>;
|
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<[],[],[]>;
|
def int_xcore_clre : Intrinsic<[],[],[]>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,8 @@ namespace {
|
||||||
Subtarget(*TM.getSubtargetImpl()) { }
|
Subtarget(*TM.getSubtargetImpl()) { }
|
||||||
|
|
||||||
SDNode *Select(SDNode *N);
|
SDNode *Select(SDNode *N);
|
||||||
|
SDNode *SelectBRIND(SDNode *N);
|
||||||
|
|
||||||
/// getI32Imm - Return a target constant with the specified value, of type
|
/// getI32Imm - Return a target constant with the specified value, of type
|
||||||
/// i32.
|
/// i32.
|
||||||
inline SDValue getI32Imm(unsigned Imm) {
|
inline SDValue getI32Imm(unsigned Imm) {
|
||||||
|
@ -154,62 +155,133 @@ bool XCoreDAGToDAGISel::SelectADDRcpii(SDValue Addr, SDValue &Base,
|
||||||
|
|
||||||
SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
|
SDNode *XCoreDAGToDAGISel::Select(SDNode *N) {
|
||||||
DebugLoc dl = N->getDebugLoc();
|
DebugLoc dl = N->getDebugLoc();
|
||||||
EVT NVT = N->getValueType(0);
|
switch (N->getOpcode()) {
|
||||||
if (NVT == MVT::i32) {
|
default: break;
|
||||||
switch (N->getOpcode()) {
|
case ISD::Constant: {
|
||||||
default: break;
|
uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
|
||||||
case ISD::Constant: {
|
if (immMskBitp(N)) {
|
||||||
uint64_t Val = cast<ConstantSDNode>(N)->getZExtValue();
|
// Transformation function: get the size of a mask
|
||||||
if (immMskBitp(N)) {
|
// Look for the first non-zero bit
|
||||||
// Transformation function: get the size of a mask
|
SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val));
|
||||||
// Look for the first non-zero bit
|
return CurDAG->getMachineNode(XCore::MKMSK_rus, dl,
|
||||||
SDValue MskSize = getI32Imm(32 - CountLeadingZeros_32(Val));
|
MVT::i32, MskSize);
|
||||||
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: {
|
else if (!isUInt<16>(Val)) {
|
||||||
SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
|
SDValue CPIdx =
|
||||||
N->getOperand(2) };
|
CurDAG->getTargetConstantPool(ConstantInt::get(
|
||||||
return CurDAG->getMachineNode(XCore::LADD_l5r, dl, MVT::i32, MVT::i32,
|
Type::getInt32Ty(*CurDAG->getContext()), Val),
|
||||||
Ops, 3);
|
TLI.getPointerTy());
|
||||||
}
|
return CurDAG->getMachineNode(XCore::LDWCP_lru6, dl, MVT::i32,
|
||||||
case XCoreISD::LSUB: {
|
MVT::Other, CPIdx,
|
||||||
SDValue Ops[] = { N->getOperand(0), N->getOperand(1),
|
CurDAG->getEntryNode());
|
||||||
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.
|
|
||||||
}
|
}
|
||||||
|
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);
|
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>;
|
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
|
// U10
|
||||||
// TODO ldwcpl, blacp
|
// TODO ldwcpl, blacp
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
declare void @llvm.xcore.setv.p1i8(i8 addrspace(1)* %r, i8* %p)
|
declare void @llvm.xcore.setv.p1i8(i8 addrspace(1)* %r, i8* %p)
|
||||||
declare i8* @llvm.xcore.waitevent()
|
declare i8* @llvm.xcore.waitevent()
|
||||||
|
declare i8* @llvm.xcore.checkevent(i8*)
|
||||||
declare void @llvm.xcore.clre()
|
declare void @llvm.xcore.clre()
|
||||||
|
|
||||||
define i32 @f(i8 addrspace(1)* %r) nounwind {
|
define i32 @f(i8 addrspace(1)* %r) nounwind {
|
||||||
|
@ -22,3 +23,22 @@ ret:
|
||||||
%retval = phi i32 [1, %L1], [2, %L2]
|
%retval = phi i32 [1, %L1], [2, %L2]
|
||||||
ret i32 %retval
|
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