[ARM] Use the load-acquire/store-release instructions optimally in AArch32.

Patch by Artyom Skrobov.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@191428 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Amara Emerson 2013-09-26 12:22:36 +00:00
parent 9637da6083
commit 268c743a3b
12 changed files with 1913 additions and 389 deletions

View File

@ -604,11 +604,17 @@ namespace ISD {
ATOMIC_STORE,
/// Val, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmp, swap)
/// For double-word atomic operations:
/// ValLo, ValHi, OUTCHAIN = ATOMIC_CMP_SWAP(INCHAIN, ptr, cmpLo, cmpHi,
/// swapLo, swapHi)
/// This corresponds to the cmpxchg instruction.
ATOMIC_CMP_SWAP,
/// Val, OUTCHAIN = ATOMIC_SWAP(INCHAIN, ptr, amt)
/// Val, OUTCHAIN = ATOMIC_LOAD_[OpName](INCHAIN, ptr, amt)
/// For double-word atomic operations:
/// ValLo, ValHi, OUTCHAIN = ATOMIC_SWAP(INCHAIN, ptr, amtLo, amtHi)
/// ValLo, ValHi, OUTCHAIN = ATOMIC_LOAD_[OpName](INCHAIN, ptr, amtLo, amtHi)
/// These correspond to the atomicrmw instruction.
ATOMIC_SWAP,
ATOMIC_LOAD_ADD,

View File

@ -677,6 +677,13 @@ public:
AtomicOrdering Ordering,
SynchronizationScope SynchScope);
/// getAtomic - Gets a node for an atomic op, produces result and chain and
/// takes N operands.
SDValue getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT, SDVTList VTList,
SDValue* Ops, unsigned NumOps, MachineMemOperand *MMO,
AtomicOrdering Ordering,
SynchronizationScope SynchScope);
/// getMemIntrinsicNode - Creates a MemIntrinsicNode that may produce a
/// result and takes a list of operands. Opcode may be INTRINSIC_VOID,
/// INTRINSIC_W_CHAIN, or a target-specific opcode with a value not

View File

@ -1073,6 +1073,7 @@ public:
///
class AtomicSDNode : public MemSDNode {
SDUse Ops[4];
SDUse* DynOps;
void InitAtomic(AtomicOrdering Ordering, SynchronizationScope SynchScope) {
// This must match encodeMemSDNodeFlags() in SelectionDAG.cpp.
@ -1100,7 +1101,7 @@ public:
SDValue Chain, SDValue Ptr,
SDValue Cmp, SDValue Swp, MachineMemOperand *MMO,
AtomicOrdering Ordering, SynchronizationScope SynchScope)
: MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) {
: MemSDNode(Opc, Order, dl, VTL, MemVT, MMO), DynOps(NULL) {
InitAtomic(Ordering, SynchScope);
InitOperands(Ops, Chain, Ptr, Cmp, Swp);
}
@ -1109,7 +1110,7 @@ public:
SDValue Chain, SDValue Ptr,
SDValue Val, MachineMemOperand *MMO,
AtomicOrdering Ordering, SynchronizationScope SynchScope)
: MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) {
: MemSDNode(Opc, Order, dl, VTL, MemVT, MMO), DynOps(NULL) {
InitAtomic(Ordering, SynchScope);
InitOperands(Ops, Chain, Ptr, Val);
}
@ -1118,10 +1119,22 @@ public:
SDValue Chain, SDValue Ptr,
MachineMemOperand *MMO,
AtomicOrdering Ordering, SynchronizationScope SynchScope)
: MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) {
: MemSDNode(Opc, Order, dl, VTL, MemVT, MMO), DynOps(NULL) {
InitAtomic(Ordering, SynchScope);
InitOperands(Ops, Chain, Ptr);
}
AtomicSDNode(unsigned Opc, unsigned Order, DebugLoc dl, SDVTList VTL, EVT MemVT,
SDValue* AllOps, unsigned NumOps,
MachineMemOperand *MMO,
AtomicOrdering Ordering, SynchronizationScope SynchScope)
: MemSDNode(Opc, Order, dl, VTL, MemVT, MMO) {
DynOps = new SDUse[NumOps];
InitAtomic(Ordering, SynchScope);
InitOperands(DynOps, AllOps, NumOps);
}
~AtomicSDNode() {
delete[] DynOps;
}
const SDValue &getBasePtr() const { return getOperand(1); }
const SDValue &getVal() const { return getOperand(2); }
@ -1852,7 +1865,7 @@ template <> struct GraphTraits<SDNode*> {
/// LargestSDNode - The largest SDNode class.
///
typedef LoadSDNode LargestSDNode;
typedef AtomicSDNode LargestSDNode;
/// MostAlignedSDNode - The SDNode class with the greatest alignment
/// requirement.

View File

@ -4106,6 +4106,29 @@ SDValue SelectionDAG::getMemset(SDValue Chain, SDLoc dl, SDValue Dst,
return CallResult.second;
}
SDValue SelectionDAG::getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT,
SDVTList VTList, SDValue* Ops, unsigned NumOps,
MachineMemOperand *MMO,
AtomicOrdering Ordering,
SynchronizationScope SynchScope) {
FoldingSetNodeID ID;
ID.AddInteger(MemVT.getRawBits());
AddNodeIDNode(ID, Opcode, VTList, Ops, NumOps);
ID.AddInteger(MMO->getPointerInfo().getAddrSpace());
void* IP = 0;
if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP)) {
cast<AtomicSDNode>(E)->refineAlignment(MMO);
return SDValue(E, 0);
}
SDNode *N = new (NodeAllocator) AtomicSDNode(Opcode, dl.getIROrder(),
dl.getDebugLoc(), VTList, MemVT,
Ops, NumOps, MMO, Ordering,
SynchScope);
CSEMap.InsertNode(N, IP);
AllNodes.push_back(N);
return SDValue(N, 0);
}
SDValue SelectionDAG::getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT,
SDValue Chain, SDValue Ptr, SDValue Cmp,
SDValue Swp, MachinePointerInfo PtrInfo,
@ -4146,23 +4169,8 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT,
EVT VT = Cmp.getValueType();
SDVTList VTs = getVTList(VT, MVT::Other);
FoldingSetNodeID ID;
ID.AddInteger(MemVT.getRawBits());
SDValue Ops[] = {Chain, Ptr, Cmp, Swp};
AddNodeIDNode(ID, Opcode, VTs, Ops, 4);
ID.AddInteger(MMO->getPointerInfo().getAddrSpace());
void* IP = 0;
if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP)) {
cast<AtomicSDNode>(E)->refineAlignment(MMO);
return SDValue(E, 0);
}
SDNode *N = new (NodeAllocator) AtomicSDNode(Opcode, dl.getIROrder(),
dl.getDebugLoc(), VTs, MemVT,
Chain, Ptr, Cmp, Swp, MMO,
Ordering, SynchScope);
CSEMap.InsertNode(N, IP);
AllNodes.push_back(N);
return SDValue(N, 0);
return getAtomic(Opcode, dl, MemVT, VTs, Ops, 4, MMO, Ordering, SynchScope);
}
SDValue SelectionDAG::getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT,
@ -4220,23 +4228,8 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT,
SDVTList VTs = Opcode == ISD::ATOMIC_STORE ? getVTList(MVT::Other) :
getVTList(VT, MVT::Other);
FoldingSetNodeID ID;
ID.AddInteger(MemVT.getRawBits());
SDValue Ops[] = {Chain, Ptr, Val};
AddNodeIDNode(ID, Opcode, VTs, Ops, 3);
ID.AddInteger(MMO->getPointerInfo().getAddrSpace());
void* IP = 0;
if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP)) {
cast<AtomicSDNode>(E)->refineAlignment(MMO);
return SDValue(E, 0);
}
SDNode *N = new (NodeAllocator) AtomicSDNode(Opcode, dl.getIROrder(),
dl.getDebugLoc(), VTs, MemVT,
Chain, Ptr, Val, MMO,
Ordering, SynchScope);
CSEMap.InsertNode(N, IP);
AllNodes.push_back(N);
return SDValue(N, 0);
return getAtomic(Opcode, dl, MemVT, VTs, Ops, 3, MMO, Ordering, SynchScope);
}
SDValue SelectionDAG::getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT,
@ -4279,23 +4272,8 @@ SDValue SelectionDAG::getAtomic(unsigned Opcode, SDLoc dl, EVT MemVT,
assert(Opcode == ISD::ATOMIC_LOAD && "Invalid Atomic Op");
SDVTList VTs = getVTList(VT, MVT::Other);
FoldingSetNodeID ID;
ID.AddInteger(MemVT.getRawBits());
SDValue Ops[] = {Chain, Ptr};
AddNodeIDNode(ID, Opcode, VTs, Ops, 2);
ID.AddInteger(MMO->getPointerInfo().getAddrSpace());
void* IP = 0;
if (SDNode *E = CSEMap.FindNodeOrInsertPos(ID, IP)) {
cast<AtomicSDNode>(E)->refineAlignment(MMO);
return SDValue(E, 0);
}
SDNode *N = new (NodeAllocator) AtomicSDNode(Opcode, dl.getIROrder(),
dl.getDebugLoc(), VTs, MemVT,
Chain, Ptr, MMO, Ordering,
SynchScope);
CSEMap.InsertNode(N, IP);
AllNodes.push_back(N);
return SDValue(N, 0);
return getAtomic(Opcode, dl, MemVT, VTs, Ops, 2, MMO, Ordering, SynchScope);
}
/// getMergeValues - Create a MERGE_VALUES node from the given operands.

View File

@ -253,7 +253,7 @@ private:
SDNode *SelectConcatVector(SDNode *N);
SDNode *SelectAtomic64(SDNode *Node, unsigned Opc);
SDNode *SelectAtomic(SDNode *N, unsigned Op8, unsigned Op16, unsigned Op32, unsigned Op64);
/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
/// inline asm expressions.
@ -2361,23 +2361,36 @@ SDNode *ARMDAGToDAGISel::SelectConcatVector(SDNode *N) {
return createDRegPairNode(VT, N->getOperand(0), N->getOperand(1));
}
SDNode *ARMDAGToDAGISel::SelectAtomic64(SDNode *Node, unsigned Opc) {
SDNode *ARMDAGToDAGISel::SelectAtomic(SDNode *Node, unsigned Op8,
unsigned Op16,unsigned Op32,
unsigned Op64) {
// Mostly direct translation to the given operations, except that we preserve
// the AtomicOrdering for use later on.
AtomicSDNode *AN = cast<AtomicSDNode>(Node);
EVT VT = AN->getMemoryVT();
unsigned Op;
SDVTList VTs = CurDAG->getVTList(AN->getValueType(0), MVT::Other);
if (VT == MVT::i8)
Op = Op8;
else if (VT == MVT::i16)
Op = Op16;
else if (VT == MVT::i32)
Op = Op32;
else if (VT == MVT::i64) {
Op = Op64;
VTs = CurDAG->getVTList(MVT::i32, MVT::i32, MVT::Other);
} else
llvm_unreachable("Unexpected atomic operation");
SmallVector<SDValue, 6> Ops;
Ops.push_back(Node->getOperand(1)); // Ptr
Ops.push_back(Node->getOperand(2)); // Low part of Val1
Ops.push_back(Node->getOperand(3)); // High part of Val1
if (Opc == ARM::ATOMCMPXCHG6432) {
Ops.push_back(Node->getOperand(4)); // Low part of Val2
Ops.push_back(Node->getOperand(5)); // High part of Val2
}
Ops.push_back(Node->getOperand(0)); // Chain
MachineSDNode::mmo_iterator MemOp = MF->allocateMemRefsArray(1);
MemOp[0] = cast<MemSDNode>(Node)->getMemOperand();
SDNode *ResNode = CurDAG->getMachineNode(Opc, SDLoc(Node),
MVT::i32, MVT::i32, MVT::Other,
Ops);
cast<MachineSDNode>(ResNode)->setMemRefs(MemOp, MemOp + 1);
return ResNode;
for (unsigned i = 1; i < AN->getNumOperands(); ++i)
Ops.push_back(AN->getOperand(i));
Ops.push_back(CurDAG->getTargetConstant(AN->getOrdering(), MVT::i32));
Ops.push_back(AN->getOperand(0)); // Chain moves to the end
return CurDAG->SelectNodeTo(Node, Op, VTs, &Ops[0], Ops.size());
}
SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
@ -3251,31 +3264,90 @@ SDNode *ARMDAGToDAGISel::Select(SDNode *N) {
case ISD::CONCAT_VECTORS:
return SelectConcatVector(N);
case ARMISD::ATOMOR64_DAG:
return SelectAtomic64(N, ARM::ATOMOR6432);
case ARMISD::ATOMXOR64_DAG:
return SelectAtomic64(N, ARM::ATOMXOR6432);
case ARMISD::ATOMADD64_DAG:
return SelectAtomic64(N, ARM::ATOMADD6432);
case ARMISD::ATOMSUB64_DAG:
return SelectAtomic64(N, ARM::ATOMSUB6432);
case ARMISD::ATOMNAND64_DAG:
return SelectAtomic64(N, ARM::ATOMNAND6432);
case ARMISD::ATOMAND64_DAG:
return SelectAtomic64(N, ARM::ATOMAND6432);
case ARMISD::ATOMSWAP64_DAG:
return SelectAtomic64(N, ARM::ATOMSWAP6432);
case ARMISD::ATOMCMPXCHG64_DAG:
return SelectAtomic64(N, ARM::ATOMCMPXCHG6432);
case ISD::ATOMIC_LOAD:
if (cast<AtomicSDNode>(N)->getMemoryVT() == MVT::i64)
return SelectAtomic(N, 0, 0, 0, ARM::ATOMIC_LOAD_I64);
else
break;
case ARMISD::ATOMMIN64_DAG:
return SelectAtomic64(N, ARM::ATOMMIN6432);
case ARMISD::ATOMUMIN64_DAG:
return SelectAtomic64(N, ARM::ATOMUMIN6432);
case ARMISD::ATOMMAX64_DAG:
return SelectAtomic64(N, ARM::ATOMMAX6432);
case ARMISD::ATOMUMAX64_DAG:
return SelectAtomic64(N, ARM::ATOMUMAX6432);
case ISD::ATOMIC_STORE:
if (cast<AtomicSDNode>(N)->getMemoryVT() == MVT::i64)
return SelectAtomic(N, 0, 0, 0, ARM::ATOMIC_STORE_I64);
else
break;
case ISD::ATOMIC_LOAD_ADD:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_ADD_I8,
ARM::ATOMIC_LOAD_ADD_I16,
ARM::ATOMIC_LOAD_ADD_I32,
ARM::ATOMIC_LOAD_ADD_I64);
case ISD::ATOMIC_LOAD_SUB:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_SUB_I8,
ARM::ATOMIC_LOAD_SUB_I16,
ARM::ATOMIC_LOAD_SUB_I32,
ARM::ATOMIC_LOAD_SUB_I64);
case ISD::ATOMIC_LOAD_AND:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_AND_I8,
ARM::ATOMIC_LOAD_AND_I16,
ARM::ATOMIC_LOAD_AND_I32,
ARM::ATOMIC_LOAD_AND_I64);
case ISD::ATOMIC_LOAD_OR:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_OR_I8,
ARM::ATOMIC_LOAD_OR_I16,
ARM::ATOMIC_LOAD_OR_I32,
ARM::ATOMIC_LOAD_OR_I64);
case ISD::ATOMIC_LOAD_XOR:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_XOR_I8,
ARM::ATOMIC_LOAD_XOR_I16,
ARM::ATOMIC_LOAD_XOR_I32,
ARM::ATOMIC_LOAD_XOR_I64);
case ISD::ATOMIC_LOAD_NAND:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_NAND_I8,
ARM::ATOMIC_LOAD_NAND_I16,
ARM::ATOMIC_LOAD_NAND_I32,
ARM::ATOMIC_LOAD_NAND_I64);
case ISD::ATOMIC_LOAD_MIN:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_MIN_I8,
ARM::ATOMIC_LOAD_MIN_I16,
ARM::ATOMIC_LOAD_MIN_I32,
ARM::ATOMIC_LOAD_MIN_I64);
case ISD::ATOMIC_LOAD_MAX:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_MAX_I8,
ARM::ATOMIC_LOAD_MAX_I16,
ARM::ATOMIC_LOAD_MAX_I32,
ARM::ATOMIC_LOAD_MAX_I64);
case ISD::ATOMIC_LOAD_UMIN:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_UMIN_I8,
ARM::ATOMIC_LOAD_UMIN_I16,
ARM::ATOMIC_LOAD_UMIN_I32,
ARM::ATOMIC_LOAD_UMIN_I64);
case ISD::ATOMIC_LOAD_UMAX:
return SelectAtomic(N,
ARM::ATOMIC_LOAD_UMAX_I8,
ARM::ATOMIC_LOAD_UMAX_I16,
ARM::ATOMIC_LOAD_UMAX_I32,
ARM::ATOMIC_LOAD_UMAX_I64);
case ISD::ATOMIC_SWAP:
return SelectAtomic(N,
ARM::ATOMIC_SWAP_I8,
ARM::ATOMIC_SWAP_I16,
ARM::ATOMIC_SWAP_I32,
ARM::ATOMIC_SWAP_I64);
case ISD::ATOMIC_CMP_SWAP:
return SelectAtomic(N,
ARM::ATOMIC_CMP_SWAP_I8,
ARM::ATOMIC_CMP_SWAP_I16,
ARM::ATOMIC_CMP_SWAP_I32,
ARM::ATOMIC_CMP_SWAP_I64);
}
return SelectCode(N);

View File

@ -769,8 +769,14 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
setOperationAction(ISD::ATOMIC_LOAD_UMIN, MVT::i64, Custom);
setOperationAction(ISD::ATOMIC_LOAD_UMAX, MVT::i64, Custom);
setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i64, Custom);
// Automatically insert fences (dmb ist) around ATOMIC_SWAP etc.
setInsertFencesForAtomic(true);
// On v8, we have particularly efficient implementations of atomic fences
// if they can be combined with nearby atomic loads and stores.
if (!Subtarget->hasV8Ops()) {
// Automatically insert fences (dmb ist) around ATOMIC_SWAP etc.
setInsertFencesForAtomic(true);
}
setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Custom);
//setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Custom);
} else {
// Set them all for expansion, which will force libcalls.
setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand);
@ -909,6 +915,44 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
setMinFunctionAlignment(Subtarget->isThumb() ? 1 : 2);
}
static void getExclusiveOperation(unsigned Size, AtomicOrdering Ord,
bool isThumb2, unsigned &LdrOpc,
unsigned &StrOpc) {
static const unsigned LoadBares[4][2] = {{ARM::LDREXB, ARM::t2LDREXB},
{ARM::LDREXH, ARM::t2LDREXH},
{ARM::LDREX, ARM::t2LDREX},
{ARM::LDREXD, ARM::t2LDREXD}};
static const unsigned LoadAcqs[4][2] = {{ARM::LDAEXB, ARM::t2LDAEXB},
{ARM::LDAEXH, ARM::t2LDAEXH},
{ARM::LDAEX, ARM::t2LDAEX},
{ARM::LDAEXD, ARM::t2LDAEXD}};
static const unsigned StoreBares[4][2] = {{ARM::STREXB, ARM::t2STREXB},
{ARM::STREXH, ARM::t2STREXH},
{ARM::STREX, ARM::t2STREX},
{ARM::STREXD, ARM::t2STREXD}};
static const unsigned StoreRels[4][2] = {{ARM::STLEXB, ARM::t2STLEXB},
{ARM::STLEXH, ARM::t2STLEXH},
{ARM::STLEX, ARM::t2STLEX},
{ARM::STLEXD, ARM::t2STLEXD}};
const unsigned (*LoadOps)[2], (*StoreOps)[2];
if (Ord == Acquire || Ord == AcquireRelease || Ord == SequentiallyConsistent)
LoadOps = LoadAcqs;
else
LoadOps = LoadBares;
if (Ord == Release || Ord == AcquireRelease || Ord == SequentiallyConsistent)
StoreOps = StoreRels;
else
StoreOps = StoreBares;
assert(isPowerOf2_32(Size) && Size <= 8 &&
"unsupported size for atomic binary op!");
LdrOpc = LoadOps[Log2_32(Size)][isThumb2];
StrOpc = StoreOps[Log2_32(Size)][isThumb2];
}
// FIXME: It might make sense to define the representative register class as the
// nearest super-register that has a non-null superset. For example, DPR_VFP2 is
// a super-register of SPR, and DPR is a superset if DPR_VFP2. Consequently,
@ -1094,19 +1138,6 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::VST2LN_UPD: return "ARMISD::VST2LN_UPD";
case ARMISD::VST3LN_UPD: return "ARMISD::VST3LN_UPD";
case ARMISD::VST4LN_UPD: return "ARMISD::VST4LN_UPD";
case ARMISD::ATOMADD64_DAG: return "ATOMADD64_DAG";
case ARMISD::ATOMSUB64_DAG: return "ATOMSUB64_DAG";
case ARMISD::ATOMOR64_DAG: return "ATOMOR64_DAG";
case ARMISD::ATOMXOR64_DAG: return "ATOMXOR64_DAG";
case ARMISD::ATOMAND64_DAG: return "ATOMAND64_DAG";
case ARMISD::ATOMNAND64_DAG: return "ATOMNAND64_DAG";
case ARMISD::ATOMSWAP64_DAG: return "ATOMSWAP64_DAG";
case ARMISD::ATOMCMPXCHG64_DAG: return "ATOMCMPXCHG64_DAG";
case ARMISD::ATOMMIN64_DAG: return "ATOMMIN64_DAG";
case ARMISD::ATOMUMIN64_DAG: return "ATOMUMIN64_DAG";
case ARMISD::ATOMMAX64_DAG: return "ATOMMAX64_DAG";
case ARMISD::ATOMUMAX64_DAG: return "ATOMUMAX64_DAG";
}
}
@ -5922,32 +5953,28 @@ static SDValue LowerAtomicLoadStore(SDValue Op, SelectionDAG &DAG) {
static void
ReplaceATOMIC_OP_64(SDNode *Node, SmallVectorImpl<SDValue>& Results,
SelectionDAG &DAG, unsigned NewOp) {
SelectionDAG &DAG) {
SDLoc dl(Node);
assert (Node->getValueType(0) == MVT::i64 &&
"Only know how to expand i64 atomics");
AtomicSDNode *AN = cast<AtomicSDNode>(Node);
SmallVector<SDValue, 6> Ops;
Ops.push_back(Node->getOperand(0)); // Chain
Ops.push_back(Node->getOperand(1)); // Ptr
// Low part of Val1
Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,
Node->getOperand(2), DAG.getIntPtrConstant(0)));
// High part of Val1
Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,
Node->getOperand(2), DAG.getIntPtrConstant(1)));
if (NewOp == ARMISD::ATOMCMPXCHG64_DAG) {
// High part of Val1
for(unsigned i=2; i<Node->getNumOperands(); i++) {
// Low part
Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,
Node->getOperand(3), DAG.getIntPtrConstant(0)));
// High part of Val2
Node->getOperand(i), DAG.getIntPtrConstant(0)));
// High part
Ops.push_back(DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32,
Node->getOperand(3), DAG.getIntPtrConstant(1)));
Node->getOperand(i), DAG.getIntPtrConstant(1)));
}
SDVTList Tys = DAG.getVTList(MVT::i32, MVT::i32, MVT::Other);
SDValue Result =
DAG.getMemIntrinsicNode(NewOp, dl, Tys, Ops.data(), Ops.size(), MVT::i64,
cast<MemSDNode>(Node)->getMemOperand());
DAG.getAtomic(Node->getOpcode(), dl, MVT::i64, Tys, Ops.data(), Ops.size(),
cast<MemSDNode>(Node)->getMemOperand(), AN->getOrdering(),
AN->getSynchScope());
SDValue OpsF[] = { Result.getValue(0), Result.getValue(1) };
Results.push_back(DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, OpsF, 2));
Results.push_back(Result.getValue(2));
@ -6073,41 +6100,21 @@ void ARMTargetLowering::ReplaceNodeResults(SDNode *N,
case ISD::READCYCLECOUNTER:
ReplaceREADCYCLECOUNTER(N, Results, DAG, Subtarget);
return;
case ISD::ATOMIC_STORE:
case ISD::ATOMIC_LOAD:
case ISD::ATOMIC_LOAD_ADD:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMADD64_DAG);
return;
case ISD::ATOMIC_LOAD_AND:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMAND64_DAG);
return;
case ISD::ATOMIC_LOAD_NAND:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMNAND64_DAG);
return;
case ISD::ATOMIC_LOAD_OR:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMOR64_DAG);
return;
case ISD::ATOMIC_LOAD_SUB:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMSUB64_DAG);
return;
case ISD::ATOMIC_LOAD_XOR:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMXOR64_DAG);
return;
case ISD::ATOMIC_SWAP:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMSWAP64_DAG);
return;
case ISD::ATOMIC_CMP_SWAP:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMCMPXCHG64_DAG);
return;
case ISD::ATOMIC_LOAD_MIN:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMMIN64_DAG);
return;
case ISD::ATOMIC_LOAD_UMIN:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMUMIN64_DAG);
return;
case ISD::ATOMIC_LOAD_MAX:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMMAX64_DAG);
return;
case ISD::ATOMIC_LOAD_UMAX:
ReplaceATOMIC_OP_64(N, Results, DAG, ARMISD::ATOMUMAX64_DAG);
ReplaceATOMIC_OP_64(N, Results, DAG);
return;
}
if (Res.getNode())
@ -6127,6 +6134,7 @@ ARMTargetLowering::EmitAtomicCmpSwap(MachineInstr *MI,
unsigned oldval = MI->getOperand(2).getReg();
unsigned newval = MI->getOperand(3).getReg();
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
AtomicOrdering Ord = static_cast<AtomicOrdering>(MI->getOperand(4).getImm());
DebugLoc dl = MI->getDebugLoc();
bool isThumb2 = Subtarget->isThumb2();
@ -6142,21 +6150,7 @@ ARMTargetLowering::EmitAtomicCmpSwap(MachineInstr *MI,
}
unsigned ldrOpc, strOpc;
switch (Size) {
default: llvm_unreachable("unsupported size for AtomicCmpSwap!");
case 1:
ldrOpc = isThumb2 ? ARM::t2LDREXB : ARM::LDREXB;
strOpc = isThumb2 ? ARM::t2STREXB : ARM::STREXB;
break;
case 2:
ldrOpc = isThumb2 ? ARM::t2LDREXH : ARM::LDREXH;
strOpc = isThumb2 ? ARM::t2STREXH : ARM::STREXH;
break;
case 4:
ldrOpc = isThumb2 ? ARM::t2LDREX : ARM::LDREX;
strOpc = isThumb2 ? ARM::t2STREX : ARM::STREX;
break;
}
getExclusiveOperation(Size, Ord, isThumb2, ldrOpc, strOpc);
MachineFunction *MF = BB->getParent();
const BasicBlock *LLVM_BB = BB->getBasicBlock();
@ -6236,6 +6230,7 @@ ARMTargetLowering::EmitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB,
unsigned dest = MI->getOperand(0).getReg();
unsigned ptr = MI->getOperand(1).getReg();
unsigned incr = MI->getOperand(2).getReg();
AtomicOrdering Ord = static_cast<AtomicOrdering>(MI->getOperand(3).getImm());
DebugLoc dl = MI->getDebugLoc();
bool isThumb2 = Subtarget->isThumb2();
@ -6243,24 +6238,11 @@ ARMTargetLowering::EmitAtomicBinary(MachineInstr *MI, MachineBasicBlock *BB,
if (isThumb2) {
MRI.constrainRegClass(dest, &ARM::rGPRRegClass);
MRI.constrainRegClass(ptr, &ARM::rGPRRegClass);
MRI.constrainRegClass(incr, &ARM::rGPRRegClass);
}
unsigned ldrOpc, strOpc;
switch (Size) {
default: llvm_unreachable("unsupported size for AtomicCmpSwap!");
case 1:
ldrOpc = isThumb2 ? ARM::t2LDREXB : ARM::LDREXB;
strOpc = isThumb2 ? ARM::t2STREXB : ARM::STREXB;
break;
case 2:
ldrOpc = isThumb2 ? ARM::t2LDREXH : ARM::LDREXH;
strOpc = isThumb2 ? ARM::t2STREXH : ARM::STREXH;
break;
case 4:
ldrOpc = isThumb2 ? ARM::t2LDREX : ARM::LDREX;
strOpc = isThumb2 ? ARM::t2STREX : ARM::STREX;
break;
}
getExclusiveOperation(Size, Ord, isThumb2, ldrOpc, strOpc);
MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB);
MachineBasicBlock *exitMBB = MF->CreateMachineBasicBlock(LLVM_BB);
@ -6344,6 +6326,7 @@ ARMTargetLowering::EmitAtomicBinaryMinMax(MachineInstr *MI,
unsigned ptr = MI->getOperand(1).getReg();
unsigned incr = MI->getOperand(2).getReg();
unsigned oldval = dest;
AtomicOrdering Ord = static_cast<AtomicOrdering>(MI->getOperand(3).getImm());
DebugLoc dl = MI->getDebugLoc();
bool isThumb2 = Subtarget->isThumb2();
@ -6351,24 +6334,20 @@ ARMTargetLowering::EmitAtomicBinaryMinMax(MachineInstr *MI,
if (isThumb2) {
MRI.constrainRegClass(dest, &ARM::rGPRRegClass);
MRI.constrainRegClass(ptr, &ARM::rGPRRegClass);
MRI.constrainRegClass(incr, &ARM::rGPRRegClass);
}
unsigned ldrOpc, strOpc, extendOpc;
getExclusiveOperation(Size, Ord, isThumb2, ldrOpc, strOpc);
switch (Size) {
default: llvm_unreachable("unsupported size for AtomicCmpSwap!");
default: llvm_unreachable("unsupported size for AtomicBinaryMinMax!");
case 1:
ldrOpc = isThumb2 ? ARM::t2LDREXB : ARM::LDREXB;
strOpc = isThumb2 ? ARM::t2STREXB : ARM::STREXB;
extendOpc = isThumb2 ? ARM::t2SXTB : ARM::SXTB;
break;
case 2:
ldrOpc = isThumb2 ? ARM::t2LDREXH : ARM::LDREXH;
strOpc = isThumb2 ? ARM::t2STREXH : ARM::STREXH;
extendOpc = isThumb2 ? ARM::t2SXTH : ARM::SXTH;
break;
case 4:
ldrOpc = isThumb2 ? ARM::t2LDREX : ARM::LDREX;
strOpc = isThumb2 ? ARM::t2STREX : ARM::STREX;
extendOpc = 0;
break;
}
@ -6412,7 +6391,10 @@ ARMTargetLowering::EmitAtomicBinaryMinMax(MachineInstr *MI,
// Sign extend the value, if necessary.
if (signExtend && extendOpc) {
oldval = MRI.createVirtualRegister(&ARM::GPRRegClass);
oldval = MRI.createVirtualRegister(isThumb2 ? &ARM::rGPRRegClass
: &ARM::GPRnopcRegClass);
if (!isThumb2)
MRI.constrainRegClass(dest, &ARM::GPRnopcRegClass);
AddDefaultPred(BuildMI(BB, dl, TII->get(extendOpc), oldval)
.addReg(dest)
.addImm(0));
@ -6450,7 +6432,7 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
unsigned Op1, unsigned Op2,
bool NeedsCarry, bool IsCmpxchg,
bool IsMinMax, ARMCC::CondCodes CC) const {
// This also handles ATOMIC_SWAP, indicated by Op1==0.
// This also handles ATOMIC_SWAP and ATOMIC_STORE, indicated by Op1==0.
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
const BasicBlock *LLVM_BB = BB->getBasicBlock();
@ -6458,11 +6440,15 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
MachineFunction::iterator It = BB;
++It;
bool isStore = (MI->getOpcode() == ARM::ATOMIC_STORE_I64);
unsigned offset = (isStore ? -2 : 0);
unsigned destlo = MI->getOperand(0).getReg();
unsigned desthi = MI->getOperand(1).getReg();
unsigned ptr = MI->getOperand(2).getReg();
unsigned vallo = MI->getOperand(3).getReg();
unsigned valhi = MI->getOperand(4).getReg();
unsigned ptr = MI->getOperand(offset+2).getReg();
unsigned vallo = MI->getOperand(offset+3).getReg();
unsigned valhi = MI->getOperand(offset+4).getReg();
unsigned OrdIdx = offset + (IsCmpxchg ? 7 : 5);
AtomicOrdering Ord = static_cast<AtomicOrdering>(MI->getOperand(OrdIdx).getImm());
DebugLoc dl = MI->getDebugLoc();
bool isThumb2 = Subtarget->isThumb2();
@ -6475,6 +6461,9 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
MRI.constrainRegClass(valhi, &ARM::rGPRRegClass);
}
unsigned ldrOpc, strOpc;
getExclusiveOperation(8, Ord, isThumb2, ldrOpc, strOpc);
MachineBasicBlock *loopMBB = MF->CreateMachineBasicBlock(LLVM_BB);
MachineBasicBlock *contBB = 0, *cont2BB = 0;
if (IsCmpxchg || IsMinMax)
@ -6514,21 +6503,23 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
// fallthrough --> exitMBB
BB = loopMBB;
// Load
if (isThumb2) {
AddDefaultPred(BuildMI(BB, dl, TII->get(ARM::t2LDREXD))
.addReg(destlo, RegState::Define)
.addReg(desthi, RegState::Define)
.addReg(ptr));
} else {
unsigned GPRPair0 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
AddDefaultPred(BuildMI(BB, dl, TII->get(ARM::LDREXD))
.addReg(GPRPair0, RegState::Define).addReg(ptr));
// Copy r2/r3 into dest. (This copy will normally be coalesced.)
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), destlo)
.addReg(GPRPair0, 0, ARM::gsub_0);
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), desthi)
.addReg(GPRPair0, 0, ARM::gsub_1);
if (!isStore) {
// Load
if (isThumb2) {
AddDefaultPred(BuildMI(BB, dl, TII->get(ldrOpc))
.addReg(destlo, RegState::Define)
.addReg(desthi, RegState::Define)
.addReg(ptr));
} else {
unsigned GPRPair0 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
AddDefaultPred(BuildMI(BB, dl, TII->get(ldrOpc))
.addReg(GPRPair0, RegState::Define).addReg(ptr));
// Copy r2/r3 into dest. (This copy will normally be coalesced.)
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), destlo)
.addReg(GPRPair0, 0, ARM::gsub_0);
BuildMI(BB, dl, TII->get(TargetOpcode::COPY), desthi)
.addReg(GPRPair0, 0, ARM::gsub_1);
}
}
unsigned StoreLo, StoreHi;
@ -6582,7 +6573,7 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
if (isThumb2) {
MRI.constrainRegClass(StoreLo, &ARM::rGPRRegClass);
MRI.constrainRegClass(StoreHi, &ARM::rGPRRegClass);
AddDefaultPred(BuildMI(BB, dl, TII->get(ARM::t2STREXD), storesuccess)
AddDefaultPred(BuildMI(BB, dl, TII->get(strOpc), storesuccess)
.addReg(StoreLo).addReg(StoreHi).addReg(ptr));
} else {
// Marshal a pair...
@ -6600,7 +6591,7 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
.addImm(ARM::gsub_1);
// ...and store it
AddDefaultPred(BuildMI(BB, dl, TII->get(ARM::STREXD), storesuccess)
AddDefaultPred(BuildMI(BB, dl, TII->get(strOpc), storesuccess)
.addReg(StorePair).addReg(ptr));
}
// Cmp+jump
@ -6621,6 +6612,51 @@ ARMTargetLowering::EmitAtomicBinary64(MachineInstr *MI, MachineBasicBlock *BB,
return BB;
}
MachineBasicBlock *
ARMTargetLowering::EmitAtomicLoad64(MachineInstr *MI, MachineBasicBlock *BB) const {
const TargetInstrInfo *TII = getTargetMachine().getInstrInfo();
unsigned destlo = MI->getOperand(0).getReg();
unsigned desthi = MI->getOperand(1).getReg();
unsigned ptr = MI->getOperand(2).getReg();
AtomicOrdering Ord = static_cast<AtomicOrdering>(MI->getOperand(3).getImm());
DebugLoc dl = MI->getDebugLoc();
bool isThumb2 = Subtarget->isThumb2();
MachineRegisterInfo &MRI = BB->getParent()->getRegInfo();
if (isThumb2) {
MRI.constrainRegClass(destlo, &ARM::rGPRRegClass);
MRI.constrainRegClass(desthi, &ARM::rGPRRegClass);
MRI.constrainRegClass(ptr, &ARM::rGPRRegClass);
}
unsigned ldrOpc, strOpc;
getExclusiveOperation(8, Ord, isThumb2, ldrOpc, strOpc);
MachineInstrBuilder MIB = BuildMI(*BB, MI, dl, TII->get(ldrOpc));
if (isThumb2) {
MIB.addReg(destlo, RegState::Define)
.addReg(desthi, RegState::Define)
.addReg(ptr);
} else {
unsigned GPRPair0 = MRI.createVirtualRegister(&ARM::GPRPairRegClass);
MIB.addReg(GPRPair0, RegState::Define).addReg(ptr);
// Copy GPRPair0 into dest. (This copy will normally be coalesced.)
BuildMI(*BB, MI, dl, TII->get(TargetOpcode::COPY), destlo)
.addReg(GPRPair0, 0, ARM::gsub_0);
BuildMI(*BB, MI, dl, TII->get(TargetOpcode::COPY), desthi)
.addReg(GPRPair0, 0, ARM::gsub_1);
}
AddDefaultPred(MIB);
MI->eraseFromParent(); // The instruction is gone now.
return BB;
}
/// SetupEntryBlockForSjLj - Insert code into the entry block that creates and
/// registers the function context.
void ARMTargetLowering::
@ -7594,46 +7630,49 @@ ARMTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
case ARM::ATOMIC_CMP_SWAP_I16: return EmitAtomicCmpSwap(MI, BB, 2);
case ARM::ATOMIC_CMP_SWAP_I32: return EmitAtomicCmpSwap(MI, BB, 4);
case ARM::ATOMIC_LOAD_I64:
return EmitAtomicLoad64(MI, BB);
case ARM::ATOMADD6432:
case ARM::ATOMIC_LOAD_ADD_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2ADDrr : ARM::ADDrr,
isThumb2 ? ARM::t2ADCrr : ARM::ADCrr,
/*NeedsCarry*/ true);
case ARM::ATOMSUB6432:
case ARM::ATOMIC_LOAD_SUB_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr,
isThumb2 ? ARM::t2SBCrr : ARM::SBCrr,
/*NeedsCarry*/ true);
case ARM::ATOMOR6432:
case ARM::ATOMIC_LOAD_OR_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2ORRrr : ARM::ORRrr,
isThumb2 ? ARM::t2ORRrr : ARM::ORRrr);
case ARM::ATOMXOR6432:
case ARM::ATOMIC_LOAD_XOR_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2EORrr : ARM::EORrr,
isThumb2 ? ARM::t2EORrr : ARM::EORrr);
case ARM::ATOMAND6432:
case ARM::ATOMIC_LOAD_AND_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2ANDrr : ARM::ANDrr,
isThumb2 ? ARM::t2ANDrr : ARM::ANDrr);
case ARM::ATOMSWAP6432:
case ARM::ATOMIC_STORE_I64:
case ARM::ATOMIC_SWAP_I64:
return EmitAtomicBinary64(MI, BB, 0, 0, false);
case ARM::ATOMCMPXCHG6432:
case ARM::ATOMIC_CMP_SWAP_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr,
isThumb2 ? ARM::t2SBCrr : ARM::SBCrr,
/*NeedsCarry*/ false, /*IsCmpxchg*/true);
case ARM::ATOMMIN6432:
case ARM::ATOMIC_LOAD_MIN_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr,
isThumb2 ? ARM::t2SBCrr : ARM::SBCrr,
/*NeedsCarry*/ true, /*IsCmpxchg*/false,
/*IsMinMax*/ true, ARMCC::LT);
case ARM::ATOMMAX6432:
case ARM::ATOMIC_LOAD_MAX_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr,
isThumb2 ? ARM::t2SBCrr : ARM::SBCrr,
/*NeedsCarry*/ true, /*IsCmpxchg*/false,
/*IsMinMax*/ true, ARMCC::GE);
case ARM::ATOMUMIN6432:
case ARM::ATOMIC_LOAD_UMIN_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr,
isThumb2 ? ARM::t2SBCrr : ARM::SBCrr,
/*NeedsCarry*/ true, /*IsCmpxchg*/false,
/*IsMinMax*/ true, ARMCC::LO);
case ARM::ATOMUMAX6432:
case ARM::ATOMIC_LOAD_UMAX_I64:
return EmitAtomicBinary64(MI, BB, isThumb2 ? ARM::t2SUBrr : ARM::SUBrr,
isThumb2 ? ARM::t2SBCrr : ARM::SBCrr,
/*NeedsCarry*/ true, /*IsCmpxchg*/false,

View File

@ -223,21 +223,7 @@ namespace llvm {
VST4_UPD,
VST2LN_UPD,
VST3LN_UPD,
VST4LN_UPD,
// 64-bit atomic ops (value split into two registers)
ATOMADD64_DAG,
ATOMSUB64_DAG,
ATOMOR64_DAG,
ATOMXOR64_DAG,
ATOMAND64_DAG,
ATOMNAND64_DAG,
ATOMSWAP64_DAG,
ATOMCMPXCHG64_DAG,
ATOMMIN64_DAG,
ATOMUMIN64_DAG,
ATOMMAX64_DAG,
ATOMUMAX64_DAG
VST4LN_UPD
};
}
@ -574,6 +560,8 @@ namespace llvm {
unsigned Size,
bool signExtend,
ARMCC::CondCodes Cond) const;
MachineBasicBlock *EmitAtomicLoad64(MachineInstr *MI,
MachineBasicBlock *BB) const;
void SetupEntryBlockForSjLj(MachineInstr *MI,
MachineBasicBlock *MBB,

View File

@ -1677,48 +1677,6 @@ PseudoInst<(outs), (ins i32imm:$amt, pred:$p), NoItinerary,
[(ARMcallseq_start timm:$amt)]>;
}
// Atomic pseudo-insts which will be lowered to ldrexd/strexd loops.
// (These pseudos use a hand-written selection code).
let usesCustomInserter = 1, Defs = [CPSR], mayLoad = 1, mayStore = 1 in {
def ATOMOR6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMXOR6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMADD6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMSUB6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMNAND6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMAND6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMSWAP6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMCMPXCHG6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$cmp1, GPR:$cmp2,
GPR:$set1, GPR:$set2),
NoItinerary, []>;
def ATOMMIN6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMUMIN6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMMAX6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
def ATOMUMAX6432 : PseudoInst<(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2),
NoItinerary, []>;
}
def HINT : AI<(outs), (ins imm0_4:$imm), MiscFrm, NoItinerary,
"hint", "\t$imm", []>, Requires<[IsARM, HasV6]> {
bits<3> imm;
@ -4329,124 +4287,219 @@ def ISB : AInoP<(outs), (ins instsyncb_opt:$opt), MiscFrm, NoItinerary,
let Inst{3-0} = opt;
}
let usesCustomInserter = 1, Defs = [CPSR] in {
// Pseudo instruction that combines movs + predicated rsbmi
// to implement integer ABS
let usesCustomInserter = 1, Defs = [CPSR] in
def ABS : ARMPseudoInst<(outs GPR:$dst), (ins GPR:$src), 8, NoItinerary, []>;
def ABS : ARMPseudoInst<(outs GPR:$dst), (ins GPR:$src), 8, NoItinerary, []>;
let usesCustomInserter = 1 in {
let Defs = [CPSR] in {
// Atomic pseudo-insts which will be lowered to ldrex/strex loops.
// (64-bit pseudos use a hand-written selection code).
let mayLoad = 1, mayStore = 1 in {
def ATOMIC_LOAD_ADD_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_add_8 GPR:$ptr, GPR:$incr))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_SUB_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_sub_8 GPR:$ptr, GPR:$incr))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_AND_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_and_8 GPR:$ptr, GPR:$incr))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_OR_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_or_8 GPR:$ptr, GPR:$incr))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_XOR_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_xor_8 GPR:$ptr, GPR:$incr))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_NAND_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_nand_8 GPR:$ptr, GPR:$incr))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_MIN_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_min_8 GPR:$ptr, GPR:$val))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_MAX_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_max_8 GPR:$ptr, GPR:$val))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_UMIN_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_umin_8 GPR:$ptr, GPR:$val))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_UMAX_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_umax_8 GPR:$ptr, GPR:$val))]>;
def ATOMIC_LOAD_ADD_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_add_16 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_SUB_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_sub_16 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_AND_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_and_16 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_OR_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_or_16 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_XOR_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_xor_16 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_NAND_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_nand_16 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_MIN_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_min_16 GPR:$ptr, GPR:$val))]>;
def ATOMIC_LOAD_MAX_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_max_16 GPR:$ptr, GPR:$val))]>;
def ATOMIC_LOAD_UMIN_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_umin_16 GPR:$ptr, GPR:$val))]>;
def ATOMIC_LOAD_UMAX_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_umax_16 GPR:$ptr, GPR:$val))]>;
def ATOMIC_LOAD_ADD_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_add_32 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_SUB_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_sub_32 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_AND_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_and_32 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_OR_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_or_32 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_XOR_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_xor_32 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_NAND_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$incr), NoItinerary,
[(set GPR:$dst, (atomic_load_nand_32 GPR:$ptr, GPR:$incr))]>;
def ATOMIC_LOAD_MIN_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_min_32 GPR:$ptr, GPR:$val))]>;
def ATOMIC_LOAD_MAX_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_max_32 GPR:$ptr, GPR:$val))]>;
def ATOMIC_LOAD_UMIN_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_umin_32 GPR:$ptr, GPR:$val))]>;
def ATOMIC_LOAD_UMAX_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$val), NoItinerary,
[(set GPR:$dst, (atomic_load_umax_32 GPR:$ptr, GPR:$val))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_SWAP_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$new), NoItinerary,
[(set GPR:$dst, (atomic_swap_8 GPR:$ptr, GPR:$new))]>;
def ATOMIC_SWAP_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$new), NoItinerary,
[(set GPR:$dst, (atomic_swap_16 GPR:$ptr, GPR:$new))]>;
def ATOMIC_SWAP_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$new), NoItinerary,
[(set GPR:$dst, (atomic_swap_32 GPR:$ptr, GPR:$new))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$new, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_CMP_SWAP_I8 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary,
[(set GPR:$dst, (atomic_cmp_swap_8 GPR:$ptr, GPR:$old, GPR:$new))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$old, GPR:$new, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_ADD_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_SUB_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_AND_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_OR_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_XOR_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_NAND_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_MIN_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_MAX_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_UMIN_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_UMAX_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_SWAP_I16 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$new, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_CMP_SWAP_I16 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary,
[(set GPR:$dst, (atomic_cmp_swap_16 GPR:$ptr, GPR:$old, GPR:$new))]>;
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$old, GPR:$new, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_ADD_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_SUB_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_AND_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_OR_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_XOR_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_NAND_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$incr, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_MIN_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_MAX_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_UMIN_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_UMAX_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$val, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_SWAP_I32 : PseudoInst<
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$new, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_CMP_SWAP_I32 : PseudoInst<
(outs GPR:$dst), (ins GPR:$ptr, GPR:$old, GPR:$new), NoItinerary,
[(set GPR:$dst, (atomic_cmp_swap_32 GPR:$ptr, GPR:$old, GPR:$new))]>;
}
(outs GPR:$dst),
(ins GPR:$ptr, GPR:$old, GPR:$new, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_ADD_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_SUB_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_AND_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_OR_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_XOR_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_NAND_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_MIN_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_MAX_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_UMIN_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_LOAD_UMAX_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_SWAP_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
def ATOMIC_CMP_SWAP_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$cmp1, GPR:$cmp2,
GPR:$set1, GPR:$set2, i32imm:$ordering),
NoItinerary, []>;
}
let mayLoad = 1 in
def ATOMIC_LOAD_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, i32imm:$ordering),
NoItinerary, []>;
let mayStore = 1 in
def ATOMIC_STORE_I64 : PseudoInst<
(outs GPR:$dst1, GPR:$dst2),
(ins GPR:$addr, GPR:$src1, GPR:$src2, i32imm:$ordering),
NoItinerary, []>;
}
let usesCustomInserter = 1 in {
@ -4560,6 +4613,35 @@ def : ARMPat<(strex_1 (and GPR:$Rt, 0xff), addr_offset_none:$addr),
def : ARMPat<(strex_2 (and GPR:$Rt, 0xffff), addr_offset_none:$addr),
(STREXH GPR:$Rt, addr_offset_none:$addr)>;
class acquiring_load<PatFrag base>
: PatFrag<(ops node:$ptr), (base node:$ptr), [{
AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getOrdering();
return Ordering == Acquire || Ordering == SequentiallyConsistent;
}]>;
def atomic_load_acquire_8 : acquiring_load<atomic_load_8>;
def atomic_load_acquire_16 : acquiring_load<atomic_load_16>;
def atomic_load_acquire_32 : acquiring_load<atomic_load_32>;
class releasing_store<PatFrag base>
: PatFrag<(ops node:$ptr, node:$val), (base node:$ptr, node:$val), [{
AtomicOrdering Ordering = cast<AtomicSDNode>(N)->getOrdering();
return Ordering == Release || Ordering == SequentiallyConsistent;
}]>;
def atomic_store_release_8 : releasing_store<atomic_store_8>;
def atomic_store_release_16 : releasing_store<atomic_store_16>;
def atomic_store_release_32 : releasing_store<atomic_store_32>;
let AddedComplexity = 8 in {
def : ARMPat<(atomic_load_acquire_8 addr_offset_none:$addr), (LDAB addr_offset_none:$addr)>;
def : ARMPat<(atomic_load_acquire_16 addr_offset_none:$addr), (LDAH addr_offset_none:$addr)>;
def : ARMPat<(atomic_load_acquire_32 addr_offset_none:$addr), (LDA addr_offset_none:$addr)>;
def : ARMPat<(atomic_store_release_8 addr_offset_none:$addr, GPR:$val), (STLB GPR:$val, addr_offset_none:$addr)>;
def : ARMPat<(atomic_store_release_16 addr_offset_none:$addr, GPR:$val), (STLH GPR:$val, addr_offset_none:$addr)>;
def : ARMPat<(atomic_store_release_32 addr_offset_none:$addr, GPR:$val), (STL GPR:$val, addr_offset_none:$addr)>;
}
// SWP/SWPB are deprecated in V6/V7.
let mayLoad = 1, mayStore = 1 in {
def SWP : AIswp<0, (outs GPRnopc:$Rt),

View File

@ -4216,6 +4216,15 @@ def : T2Pat<(atomic_store_32 t2addrmode_negimm8:$addr, GPR:$val),
def : T2Pat<(atomic_store_32 t2addrmode_so_reg:$addr, GPR:$val),
(t2STRs GPR:$val, t2addrmode_so_reg:$addr)>;
let AddedComplexity = 8 in {
def : T2Pat<(atomic_load_acquire_8 addr_offset_none:$addr), (t2LDAB addr_offset_none:$addr)>;
def : T2Pat<(atomic_load_acquire_16 addr_offset_none:$addr), (t2LDAH addr_offset_none:$addr)>;
def : T2Pat<(atomic_load_acquire_32 addr_offset_none:$addr), (t2LDA addr_offset_none:$addr)>;
def : T2Pat<(atomic_store_release_8 addr_offset_none:$addr, GPR:$val), (t2STLB GPR:$val, addr_offset_none:$addr)>;
def : T2Pat<(atomic_store_release_16 addr_offset_none:$addr, GPR:$val), (t2STLH GPR:$val, addr_offset_none:$addr)>;
def : T2Pat<(atomic_store_release_32 addr_offset_none:$addr, GPR:$val), (t2STL GPR:$val, addr_offset_none:$addr)>;
}
//===----------------------------------------------------------------------===//
// Assembler aliases

View File

@ -94,7 +94,7 @@ std::string ARM_MC::ParseARMTriple(StringRef TT, StringRef CPU) {
unsigned SubVer = TT[Idx];
if (SubVer == '8') {
// FIXME: Parse v8 features
ARMArchFeature = "+v8";
ARMArchFeature = "+v8,+db";
} else if (SubVer == '7') {
if (Len >= Idx+2 && TT[Idx+1] == 'm') {
isThumb = true;

View File

@ -175,28 +175,14 @@ define i64 @test7(i64* %ptr, i64 %val1, i64 %val2) {
ret i64 %r
}
; Compiles down to cmpxchg
; FIXME: Should compile to a single ldrexd
; Compiles down to a single ldrexd
define i64 @test8(i64* %ptr) {
; CHECK-LABEL: test8:
; CHECK: ldrexd [[REG1:(r[0-9]?[02468])]], [[REG2:(r[0-9]?[13579])]]
; CHECK: cmp [[REG1]]
; CHECK: cmpeq [[REG2]]
; CHECK: bne
; CHECK: strexd {{[a-z0-9]+}}, {{r[0-9]?[02468]}}, {{r[0-9]?[13579]}}
; CHECK: cmp
; CHECK: bne
; CHECK: dmb {{ish$}}
; CHECK-THUMB-LABEL: test8:
; CHECK-THUMB: ldrexd [[REG1:[a-z0-9]+]], [[REG2:[a-z0-9]+]]
; CHECK-THUMB: cmp [[REG1]]
; CHECK-THUMB: it eq
; CHECK-THUMB: cmpeq [[REG2]]
; CHECK-THUMB: bne
; CHECK-THUMB: strexd {{[a-z0-9]+}}, {{[a-z0-9]+}}, {{[a-z0-9]+}}
; CHECK-THUMB: cmp
; CHECK-THUMB: bne
; CHECK-THUMB: dmb {{ish$}}
%r = load atomic i64* %ptr seq_cst, align 8

File diff suppressed because it is too large Load Diff