mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-24 19:52:54 +01:00
Add Expand-to-libcall support for additional atomics. This covers the usual
entries used by llvm-gcc. *_[U]MIN and such can be added later if needed. This enables the front ends to simplify handling of the atomic intrinsics by removing the target-specific decision about which targets can handle the intrinsics. llvm-svn: 106321
This commit is contained in:
parent
e77d313369
commit
91aae1c534
@ -247,6 +247,36 @@ namespace RTLIB {
|
||||
// EXCEPTION HANDLING
|
||||
UNWIND_RESUME,
|
||||
|
||||
// Family ATOMICs
|
||||
SYNC_VAL_COMPARE_AND_SWAP_1,
|
||||
SYNC_VAL_COMPARE_AND_SWAP_2,
|
||||
SYNC_VAL_COMPARE_AND_SWAP_4,
|
||||
SYNC_VAL_COMPARE_AND_SWAP_8,
|
||||
SYNC_FETCH_AND_ADD_1,
|
||||
SYNC_FETCH_AND_ADD_2,
|
||||
SYNC_FETCH_AND_ADD_4,
|
||||
SYNC_FETCH_AND_ADD_8,
|
||||
SYNC_FETCH_AND_SUB_1,
|
||||
SYNC_FETCH_AND_SUB_2,
|
||||
SYNC_FETCH_AND_SUB_4,
|
||||
SYNC_FETCH_AND_SUB_8,
|
||||
SYNC_FETCH_AND_AND_1,
|
||||
SYNC_FETCH_AND_AND_2,
|
||||
SYNC_FETCH_AND_AND_4,
|
||||
SYNC_FETCH_AND_AND_8,
|
||||
SYNC_FETCH_AND_OR_1,
|
||||
SYNC_FETCH_AND_OR_2,
|
||||
SYNC_FETCH_AND_OR_4,
|
||||
SYNC_FETCH_AND_OR_8,
|
||||
SYNC_FETCH_AND_XOR_1,
|
||||
SYNC_FETCH_AND_XOR_2,
|
||||
SYNC_FETCH_AND_XOR_4,
|
||||
SYNC_FETCH_AND_XOR_8,
|
||||
SYNC_FETCH_AND_NAND_1,
|
||||
SYNC_FETCH_AND_NAND_2,
|
||||
SYNC_FETCH_AND_NAND_4,
|
||||
SYNC_FETCH_AND_NAND_8,
|
||||
|
||||
UNKNOWN_LIBCALL
|
||||
};
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "llvm/LLVMContext.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
@ -143,6 +144,8 @@ private:
|
||||
DebugLoc dl);
|
||||
|
||||
SDValue ExpandLibCall(RTLIB::Libcall LC, SDNode *Node, bool isSigned);
|
||||
std::pair<SDValue, SDValue> ExpandChainLibCall(RTLIB::Libcall LC,
|
||||
SDNode *Node, bool isSigned);
|
||||
SDValue ExpandFPLibCall(SDNode *Node, RTLIB::Libcall Call_F32,
|
||||
RTLIB::Libcall Call_F64, RTLIB::Libcall Call_F80,
|
||||
RTLIB::Libcall Call_PPCF128);
|
||||
@ -172,6 +175,8 @@ private:
|
||||
SDValue ExpandExtractFromVectorThroughStack(SDValue Op);
|
||||
SDValue ExpandVectorBuildThroughStack(SDNode* Node);
|
||||
|
||||
std::pair<SDValue, SDValue> ExpandAtomic(SDNode *Node);
|
||||
|
||||
void ExpandNode(SDNode *Node, SmallVectorImpl<SDValue> &Results);
|
||||
void PromoteNode(SDNode *Node, SmallVectorImpl<SDValue> &Results);
|
||||
};
|
||||
@ -1941,6 +1946,44 @@ SDValue SelectionDAGLegalize::ExpandLibCall(RTLIB::Libcall LC, SDNode *Node,
|
||||
return CallInfo.first;
|
||||
}
|
||||
|
||||
// ExpandChainLibCall - Expand a node into a call to a libcall. Similar to
|
||||
// ExpandLibCall except that the first operand is the in-chain.
|
||||
std::pair<SDValue, SDValue>
|
||||
SelectionDAGLegalize::ExpandChainLibCall(RTLIB::Libcall LC,
|
||||
SDNode *Node,
|
||||
bool isSigned) {
|
||||
assert(!IsLegalizingCall && "Cannot overlap legalization of calls!");
|
||||
SDValue InChain = Node->getOperand(0);
|
||||
|
||||
TargetLowering::ArgListTy Args;
|
||||
TargetLowering::ArgListEntry Entry;
|
||||
for (unsigned i = 1, e = Node->getNumOperands(); i != e; ++i) {
|
||||
EVT ArgVT = Node->getOperand(i).getValueType();
|
||||
const Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext());
|
||||
Entry.Node = Node->getOperand(i);
|
||||
Entry.Ty = ArgTy;
|
||||
Entry.isSExt = isSigned;
|
||||
Entry.isZExt = !isSigned;
|
||||
Args.push_back(Entry);
|
||||
}
|
||||
SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC),
|
||||
TLI.getPointerTy());
|
||||
|
||||
// Splice the libcall in wherever FindInputOutputChains tells us to.
|
||||
const Type *RetTy = Node->getValueType(0).getTypeForEVT(*DAG.getContext());
|
||||
std::pair<SDValue, SDValue> CallInfo =
|
||||
TLI.LowerCallTo(InChain, RetTy, isSigned, !isSigned, false, false,
|
||||
0, TLI.getLibcallCallingConv(LC), false,
|
||||
/*isReturnValueUsed=*/true,
|
||||
Callee, Args, DAG, Node->getDebugLoc());
|
||||
|
||||
// Legalize the call sequence, starting with the chain. This will advance
|
||||
// the LastCALLSEQ_END to the legalized version of the CALLSEQ_END node that
|
||||
// was added by LowerCallTo (guaranteeing proper serialization of calls).
|
||||
LegalizeOp(CallInfo.second);
|
||||
return CallInfo;
|
||||
}
|
||||
|
||||
SDValue SelectionDAGLegalize::ExpandFPLibCall(SDNode* Node,
|
||||
RTLIB::Libcall Call_F32,
|
||||
RTLIB::Libcall Call_F64,
|
||||
@ -2347,6 +2390,83 @@ SDValue SelectionDAGLegalize::ExpandBitCount(unsigned Opc, SDValue Op,
|
||||
}
|
||||
}
|
||||
|
||||
std::pair <SDValue, SDValue> SelectionDAGLegalize::ExpandAtomic(SDNode *Node) {
|
||||
unsigned Opc = Node->getOpcode();
|
||||
MVT VT = cast<AtomicSDNode>(Node)->getMemoryVT().getSimpleVT();
|
||||
RTLIB::Libcall LC;
|
||||
|
||||
switch (Opc) {
|
||||
default:
|
||||
llvm_unreachable("Unhandled atomic intrinsic Expand!");
|
||||
break;
|
||||
case ISD::ATOMIC_CMP_SWAP:
|
||||
switch (VT.SimpleTy) {
|
||||
default: llvm_unreachable("Unexpected value type for atomic!");
|
||||
case MVT::i8: LC = RTLIB::SYNC_VAL_COMPARE_AND_SWAP_1; break;
|
||||
case MVT::i16: LC = RTLIB::SYNC_VAL_COMPARE_AND_SWAP_2; break;
|
||||
case MVT::i32: LC = RTLIB::SYNC_VAL_COMPARE_AND_SWAP_4; break;
|
||||
case MVT::i64: LC = RTLIB::SYNC_VAL_COMPARE_AND_SWAP_8; break;
|
||||
}
|
||||
break;
|
||||
case ISD::ATOMIC_LOAD_ADD:
|
||||
switch (VT.SimpleTy) {
|
||||
default: llvm_unreachable("Unexpected value type for atomic!");
|
||||
case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_ADD_1; break;
|
||||
case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_ADD_2; break;
|
||||
case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_ADD_4; break;
|
||||
case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_ADD_8; break;
|
||||
}
|
||||
break;
|
||||
case ISD::ATOMIC_LOAD_SUB:
|
||||
switch (VT.SimpleTy) {
|
||||
default: llvm_unreachable("Unexpected value type for atomic!");
|
||||
case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_SUB_1; break;
|
||||
case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_SUB_2; break;
|
||||
case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_SUB_4; break;
|
||||
case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_SUB_8; break;
|
||||
}
|
||||
break;
|
||||
case ISD::ATOMIC_LOAD_AND:
|
||||
switch (VT.SimpleTy) {
|
||||
default: llvm_unreachable("Unexpected value type for atomic!");
|
||||
case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_AND_1; break;
|
||||
case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_AND_2; break;
|
||||
case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_AND_4; break;
|
||||
case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_AND_8; break;
|
||||
}
|
||||
break;
|
||||
case ISD::ATOMIC_LOAD_OR:
|
||||
switch (VT.SimpleTy) {
|
||||
default: llvm_unreachable("Unexpected value type for atomic!");
|
||||
case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_OR_1; break;
|
||||
case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_OR_2; break;
|
||||
case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_OR_4; break;
|
||||
case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_OR_8; break;
|
||||
}
|
||||
break;
|
||||
case ISD::ATOMIC_LOAD_XOR:
|
||||
switch (VT.SimpleTy) {
|
||||
default: llvm_unreachable("Unexpected value type for atomic!");
|
||||
case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_XOR_1; break;
|
||||
case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_XOR_2; break;
|
||||
case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_XOR_4; break;
|
||||
case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_XOR_8; break;
|
||||
}
|
||||
break;
|
||||
case ISD::ATOMIC_LOAD_NAND:
|
||||
switch (VT.SimpleTy) {
|
||||
default: llvm_unreachable("Unexpected value type for atomic!");
|
||||
case MVT::i8: LC = RTLIB::SYNC_FETCH_AND_NAND_1; break;
|
||||
case MVT::i16: LC = RTLIB::SYNC_FETCH_AND_NAND_2; break;
|
||||
case MVT::i32: LC = RTLIB::SYNC_FETCH_AND_NAND_4; break;
|
||||
case MVT::i64: LC = RTLIB::SYNC_FETCH_AND_NAND_8; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return ExpandChainLibCall(LC, Node, false);
|
||||
}
|
||||
|
||||
void SelectionDAGLegalize::ExpandNode(SDNode *Node,
|
||||
SmallVectorImpl<SDValue> &Results) {
|
||||
DebugLoc dl = Node->getDebugLoc();
|
||||
@ -2403,11 +2523,11 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node,
|
||||
case ISD::ATOMIC_LOAD_MAX:
|
||||
case ISD::ATOMIC_LOAD_UMIN:
|
||||
case ISD::ATOMIC_LOAD_UMAX:
|
||||
case ISD::ATOMIC_CMP_SWAP: {
|
||||
assert (0 && "atomic intrinsic not lowered!");
|
||||
Results.push_back(Node->getOperand(0));
|
||||
case ISD::ATOMIC_CMP_SWAP:
|
||||
std::pair<SDValue, SDValue> Tmp = ExpandAtomic(Node);
|
||||
Results.push_back(Tmp.first);
|
||||
Results.push_back(Tmp.second);
|
||||
break;
|
||||
}
|
||||
case ISD::DYNAMIC_STACKALLOC:
|
||||
ExpandDYNAMIC_STACKALLOC(Node, Results);
|
||||
break;
|
||||
|
@ -261,6 +261,34 @@ static void InitLibcallNames(const char **Names) {
|
||||
Names[RTLIB::MEMMOVE] = "memmove";
|
||||
Names[RTLIB::MEMSET] = "memset";
|
||||
Names[RTLIB::UNWIND_RESUME] = "_Unwind_Resume";
|
||||
Names[RTLIB::SYNC_VAL_COMPARE_AND_SWAP_1] = "__sync_val_compare_and_swap_1";
|
||||
Names[RTLIB::SYNC_VAL_COMPARE_AND_SWAP_2] = "__sync_val_compare_and_swap_2";
|
||||
Names[RTLIB::SYNC_VAL_COMPARE_AND_SWAP_4] = "__sync_val_compare_and_swap_4";
|
||||
Names[RTLIB::SYNC_VAL_COMPARE_AND_SWAP_8] = "__sync_val_compare_and_swap_8";
|
||||
Names[RTLIB::SYNC_FETCH_AND_ADD_1] = "__sync_fetch_and_add_1";
|
||||
Names[RTLIB::SYNC_FETCH_AND_ADD_2] = "__sync_fetch_and_add_2";
|
||||
Names[RTLIB::SYNC_FETCH_AND_ADD_4] = "__sync_fetch_and_add_4";
|
||||
Names[RTLIB::SYNC_FETCH_AND_ADD_8] = "__sync_fetch_and_add_8";
|
||||
Names[RTLIB::SYNC_FETCH_AND_SUB_1] = "__sync_fetch_and_sub_1";
|
||||
Names[RTLIB::SYNC_FETCH_AND_SUB_2] = "__sync_fetch_and_sub_2";
|
||||
Names[RTLIB::SYNC_FETCH_AND_SUB_4] = "__sync_fetch_and_sub_4";
|
||||
Names[RTLIB::SYNC_FETCH_AND_SUB_8] = "__sync_fetch_and_sub_8";
|
||||
Names[RTLIB::SYNC_FETCH_AND_AND_1] = "__sync_fetch_and_and_1";
|
||||
Names[RTLIB::SYNC_FETCH_AND_AND_2] = "__sync_fetch_and_and_2";
|
||||
Names[RTLIB::SYNC_FETCH_AND_AND_4] = "__sync_fetch_and_and_4";
|
||||
Names[RTLIB::SYNC_FETCH_AND_AND_8] = "__sync_fetch_and_and_8";
|
||||
Names[RTLIB::SYNC_FETCH_AND_OR_1] = "__sync_fetch_and_or_1";
|
||||
Names[RTLIB::SYNC_FETCH_AND_OR_2] = "__sync_fetch_and_or_2";
|
||||
Names[RTLIB::SYNC_FETCH_AND_OR_4] = "__sync_fetch_and_or_4";
|
||||
Names[RTLIB::SYNC_FETCH_AND_OR_8] = "__sync_fetch_and_or_8";
|
||||
Names[RTLIB::SYNC_FETCH_AND_XOR_1] = "__sync_fetch_and_xor_1";
|
||||
Names[RTLIB::SYNC_FETCH_AND_XOR_2] = "__sync_fetch_and_xor_2";
|
||||
Names[RTLIB::SYNC_FETCH_AND_XOR_4] = "__sync_fetch_and-xor_4";
|
||||
Names[RTLIB::SYNC_FETCH_AND_XOR_8] = "__sync_fetch_and_xor_8";
|
||||
Names[RTLIB::SYNC_FETCH_AND_NAND_1] = "__sync_fetch_and_nand_1";
|
||||
Names[RTLIB::SYNC_FETCH_AND_NAND_2] = "__sync_fetch_and_nand_2";
|
||||
Names[RTLIB::SYNC_FETCH_AND_NAND_4] = "__sync_fetch_and_nand_4";
|
||||
Names[RTLIB::SYNC_FETCH_AND_NAND_8] = "__sync_fetch_and_nand_8";
|
||||
}
|
||||
|
||||
/// InitLibcallCallingConvs - Set default libcall CallingConvs.
|
||||
|
Loading…
Reference in New Issue
Block a user