#include "XCoreISelLowering.h"
#include "XCoreMachineFunctionInfo.h"
#include "XCore.h"
+#include "XCoreTargetObjectFile.h"
#include "XCoreTargetMachine.h"
#include "XCoreSubtarget.h"
#include "llvm/DerivedTypes.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
#include "llvm/ADT/VectorExtras.h"
#include <queue>
#include <set>
}
XCoreTargetLowering::XCoreTargetLowering(XCoreTargetMachine &XTM)
- : TargetLowering(XTM),
+ : TargetLowering(XTM, new XCoreTargetObjectFile()),
TM(XTM),
Subtarget(*XTM.getSubtargetImpl()) {
setIntDivIsCheap(false);
setShiftAmountType(MVT::i32);
- // shl X, 32 == 0
- setShiftAmountFlavor(Extend);
setStackPointerRegisterToSaveRestore(XCore::SP);
setSchedulingPreference(SchedulingForRegPressure);
setLoadExtAction(ISD::SEXTLOAD, MVT::i8, Expand);
setLoadExtAction(ISD::ZEXTLOAD, MVT::i16, Expand);
-
+
+ // Custom expand misaligned loads / stores.
+ setOperationAction(ISD::LOAD, MVT::i32, Custom);
+ setOperationAction(ISD::STORE, MVT::i32, Custom);
+
// Varargs
setOperationAction(ISD::VAEND, MVT::Other, Expand);
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
// Debug
setOperationAction(ISD::DBG_STOPPOINT, MVT::Other, Expand);
setOperationAction(ISD::DEBUG_LOC, MVT::Other, Expand);
+
+ maxStoresPerMemset = 4;
+ maxStoresPerMemmove = maxStoresPerMemcpy = 2;
+
+ // We have target-specific dag combine patterns for the following nodes:
+ setTargetDAGCombine(ISD::STORE);
}
SDValue XCoreTargetLowering::
case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
+ case ISD::LOAD: return LowerLOAD(Op, DAG);
+ case ISD::STORE: return LowerSTORE(Op, DAG);
case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG);
case ISD::VAARG: return LowerVAARG(Op, DAG);
case ISD::VASTART: return LowerVASTART(Op, DAG);
const Type *Ty = cast<PointerType>(GV->getType())->getElementType();
if (!Ty->isSized() || isZeroLengthArray(Ty)) {
#ifndef NDEBUG
- cerr << "Size of thread local object " << GVar->getName()
- << " is unknown\n";
+ errs() << "Size of thread local object " << GVar->getName()
+ << " is unknown\n";
#endif
llvm_unreachable(0);
}
return DAG.getNode(XCoreISD::DPRelativeWrapper, dl, MVT::i32, JTI);
}
+static bool
+IsWordAlignedBasePlusConstantOffset(SDValue Addr, SDValue &AlignedBase,
+ int64_t &Offset)
+{
+ if (Addr.getOpcode() != ISD::ADD) {
+ return false;
+ }
+ ConstantSDNode *CN = 0;
+ if (!(CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))) {
+ return false;
+ }
+ int64_t off = CN->getSExtValue();
+ const SDValue &Base = Addr.getOperand(0);
+ const SDValue *Root = &Base;
+ if (Base.getOpcode() == ISD::ADD &&
+ Base.getOperand(1).getOpcode() == ISD::SHL) {
+ ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Base.getOperand(1)
+ .getOperand(1));
+ if (CN && (CN->getSExtValue() >= 2)) {
+ Root = &Base.getOperand(0);
+ }
+ }
+ if (isa<FrameIndexSDNode>(*Root)) {
+ // All frame indicies are word aligned
+ AlignedBase = Base;
+ Offset = off;
+ return true;
+ }
+ if (Root->getOpcode() == XCoreISD::DPRelativeWrapper ||
+ Root->getOpcode() == XCoreISD::CPRelativeWrapper) {
+ // All dp / cp relative addresses are word aligned
+ AlignedBase = Base;
+ Offset = off;
+ return true;
+ }
+ return false;
+}
+
+SDValue XCoreTargetLowering::
+LowerLOAD(SDValue Op, SelectionDAG &DAG)
+{
+ LoadSDNode *LD = cast<LoadSDNode>(Op);
+ assert(LD->getExtensionType() == ISD::NON_EXTLOAD && "Unexpected extension type");
+ assert(LD->getMemoryVT() == MVT::i32 && "Unexpected load MVT");
+ if (allowsUnalignedMemoryAccesses()) {
+ return SDValue();
+ }
+ unsigned ABIAlignment = getTargetData()->
+ getABITypeAlignment(LD->getMemoryVT().getTypeForMVT());
+ // Leave aligned load alone.
+ if (LD->getAlignment() >= ABIAlignment) {
+ return SDValue();
+ }
+ SDValue Chain = LD->getChain();
+ SDValue BasePtr = LD->getBasePtr();
+ DebugLoc dl = Op.getDebugLoc();
+
+ SDValue Base;
+ int64_t Offset;
+ if (!LD->isVolatile() &&
+ IsWordAlignedBasePlusConstantOffset(BasePtr, Base, Offset)) {
+ if (Offset % 4 == 0) {
+ // We've managed to infer better alignment information than the load
+ // already has. Use an aligned load.
+ return DAG.getLoad(getPointerTy(), dl, Chain, BasePtr, NULL, 4);
+ }
+ // Lower to
+ // ldw low, base[offset >> 2]
+ // ldw high, base[(offset >> 2) + 1]
+ // shr low_shifted, low, (offset & 0x3) * 8
+ // shl high_shifted, high, 32 - (offset & 0x3) * 8
+ // or result, low_shifted, high_shifted
+ SDValue LowOffset = DAG.getConstant(Offset & ~0x3, MVT::i32);
+ SDValue HighOffset = DAG.getConstant((Offset & ~0x3) + 4, MVT::i32);
+ SDValue LowShift = DAG.getConstant((Offset & 0x3) * 8, MVT::i32);
+ SDValue HighShift = DAG.getConstant(32 - (Offset & 0x3) * 8, MVT::i32);
+
+ SDValue LowAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, Base, LowOffset);
+ SDValue HighAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, Base, HighOffset);
+
+ SDValue Low = DAG.getLoad(getPointerTy(), dl, Chain,
+ LowAddr, NULL, 4);
+ SDValue High = DAG.getLoad(getPointerTy(), dl, Chain,
+ HighAddr, NULL, 4);
+ SDValue LowShifted = DAG.getNode(ISD::SRL, dl, MVT::i32, Low, LowShift);
+ SDValue HighShifted = DAG.getNode(ISD::SHL, dl, MVT::i32, High, HighShift);
+ SDValue Result = DAG.getNode(ISD::OR, dl, MVT::i32, LowShifted, HighShifted);
+ Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Low.getValue(1),
+ High.getValue(1));
+ SDValue Ops[] = { Result, Chain };
+ return DAG.getMergeValues(Ops, 2, dl);
+ }
+
+ if (LD->getAlignment() == 2) {
+ int SVOffset = LD->getSrcValueOffset();
+ SDValue Low = DAG.getExtLoad(ISD::ZEXTLOAD, dl, MVT::i32, Chain,
+ BasePtr, LD->getSrcValue(), SVOffset, MVT::i16,
+ LD->isVolatile(), 2);
+ SDValue HighAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, BasePtr,
+ DAG.getConstant(2, MVT::i32));
+ SDValue High = DAG.getExtLoad(ISD::EXTLOAD, dl, MVT::i32, Chain,
+ HighAddr, LD->getSrcValue(), SVOffset + 2,
+ MVT::i16, LD->isVolatile(), 2);
+ SDValue HighShifted = DAG.getNode(ISD::SHL, dl, MVT::i32, High,
+ DAG.getConstant(16, MVT::i32));
+ SDValue Result = DAG.getNode(ISD::OR, dl, MVT::i32, Low, HighShifted);
+ Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Low.getValue(1),
+ High.getValue(1));
+ SDValue Ops[] = { Result, Chain };
+ return DAG.getMergeValues(Ops, 2, dl);
+ }
+
+ // Lower to a call to __misaligned_load(BasePtr).
+ const Type *IntPtrTy = getTargetData()->getIntPtrType();
+ TargetLowering::ArgListTy Args;
+ TargetLowering::ArgListEntry Entry;
+
+ Entry.Ty = IntPtrTy;
+ Entry.Node = BasePtr;
+ Args.push_back(Entry);
+
+ std::pair<SDValue, SDValue> CallResult =
+ LowerCallTo(Chain, IntPtrTy, false, false,
+ false, false, 0, CallingConv::C, false,
+ DAG.getExternalSymbol("__misaligned_load", getPointerTy()),
+ Args, DAG, dl);
+
+ SDValue Ops[] =
+ { CallResult.first, CallResult.second };
+
+ return DAG.getMergeValues(Ops, 2, dl);
+}
+
+SDValue XCoreTargetLowering::
+LowerSTORE(SDValue Op, SelectionDAG &DAG)
+{
+ StoreSDNode *ST = cast<StoreSDNode>(Op);
+ assert(!ST->isTruncatingStore() && "Unexpected store type");
+ assert(ST->getMemoryVT() == MVT::i32 && "Unexpected store MVT");
+ if (allowsUnalignedMemoryAccesses()) {
+ return SDValue();
+ }
+ unsigned ABIAlignment = getTargetData()->
+ getABITypeAlignment(ST->getMemoryVT().getTypeForMVT());
+ // Leave aligned store alone.
+ if (ST->getAlignment() >= ABIAlignment) {
+ return SDValue();
+ }
+ SDValue Chain = ST->getChain();
+ SDValue BasePtr = ST->getBasePtr();
+ SDValue Value = ST->getValue();
+ DebugLoc dl = Op.getDebugLoc();
+
+ if (ST->getAlignment() == 2) {
+ int SVOffset = ST->getSrcValueOffset();
+ SDValue Low = Value;
+ SDValue High = DAG.getNode(ISD::SRL, dl, MVT::i32, Value,
+ DAG.getConstant(16, MVT::i32));
+ SDValue StoreLow = DAG.getTruncStore(Chain, dl, Low, BasePtr,
+ ST->getSrcValue(), SVOffset, MVT::i16,
+ ST->isVolatile(), 2);
+ SDValue HighAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, BasePtr,
+ DAG.getConstant(2, MVT::i32));
+ SDValue StoreHigh = DAG.getTruncStore(Chain, dl, High, HighAddr,
+ ST->getSrcValue(), SVOffset + 2,
+ MVT::i16, ST->isVolatile(), 2);
+ return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, StoreLow, StoreHigh);
+ }
+
+ // Lower to a call to __misaligned_store(BasePtr, Value).
+ const Type *IntPtrTy = getTargetData()->getIntPtrType();
+ TargetLowering::ArgListTy Args;
+ TargetLowering::ArgListEntry Entry;
+
+ Entry.Ty = IntPtrTy;
+ Entry.Node = BasePtr;
+ Args.push_back(Entry);
+
+ Entry.Node = Value;
+ Args.push_back(Entry);
+
+ std::pair<SDValue, SDValue> CallResult =
+ LowerCallTo(Chain, Type::VoidTy, false, false,
+ false, false, 0, CallingConv::C, false,
+ DAG.getExternalSymbol("__misaligned_store", getPointerTy()),
+ Args, DAG, dl);
+
+ return CallResult.second;
+}
+
SDValue XCoreTargetLowering::
ExpandADDSUB(SDNode *N, SelectionDAG &DAG)
{
// Analyze operands of the call, assigning locations to each operand.
SmallVector<CCValAssign, 16> ArgLocs;
- CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs, DAG.getContext());
+ CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs, *DAG.getContext());
// The ABI dictates there should be one stack slot available to the callee
// on function entry (for saving lr).
// Assign locations to each value returned by this call.
SmallVector<CCValAssign, 16> RVLocs;
CCState CCInfo(CallingConv, isVarArg, getTargetMachine(),
- RVLocs, DAG.getContext());
+ RVLocs, *DAG.getContext());
CCInfo.AnalyzeCallResult(TheCall, RetCC_XCore);
SmallVector<SDValue, 8> ResultVals;
// Assign locations to all of the incoming arguments.
SmallVector<CCValAssign, 16> ArgLocs;
- CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs, DAG.getContext());
+ CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs, *DAG.getContext());
CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_XCore);
default:
{
#ifndef NDEBUG
- cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: "
- << RegVT.getSimpleVT() << "\n";
+ errs() << "LowerFORMAL_ARGUMENTS Unhandled argument type: "
+ << RegVT.getSimpleVT() << "\n";
#endif
llvm_unreachable(0);
}
// Load the argument to a virtual register
unsigned ObjSize = VA.getLocVT().getSizeInBits()/8;
if (ObjSize > StackSlotSize) {
- cerr << "LowerFORMAL_ARGUMENTS Unhandled argument type: "
- << VA.getLocVT().getSimpleVT()
- << "\n";
+ errs() << "LowerFORMAL_ARGUMENTS Unhandled argument type: "
+ << VA.getLocVT().getSimpleVT()
+ << "\n";
}
// Create the frame index object for this incoming parameter...
int FI = MFI->CreateFixedObject(ObjSize,
DebugLoc dl = Op.getDebugLoc();
// CCState - Info about the registers and stack slot.
- CCState CCInfo(CC, isVarArg, getTargetMachine(), RVLocs, DAG.getContext());
+ CCState CCInfo(CC, isVarArg, getTargetMachine(), RVLocs, *DAG.getContext());
// Analize return values of ISD::RET
CCInfo.AnalyzeReturn(Op.getNode(), RetCC_XCore);
return BB;
}
+//===----------------------------------------------------------------------===//
+// Target Optimization Hooks
+//===----------------------------------------------------------------------===//
+
+SDValue XCoreTargetLowering::PerformDAGCombine(SDNode *N,
+ DAGCombinerInfo &DCI) const {
+ SelectionDAG &DAG = DCI.DAG;
+ DebugLoc dl = N->getDebugLoc();
+ switch (N->getOpcode()) {
+ default: break;
+ case ISD::STORE: {
+ // Replace unaligned store of unaligned load with memmove.
+ StoreSDNode *ST = cast<StoreSDNode>(N);
+ if (!DCI.isBeforeLegalize() || allowsUnalignedMemoryAccesses() ||
+ ST->isVolatile() || ST->isIndexed()) {
+ break;
+ }
+ SDValue Chain = ST->getChain();
+
+ unsigned StoreBits = ST->getMemoryVT().getStoreSizeInBits();
+ if (StoreBits % 8) {
+ break;
+ }
+ unsigned ABIAlignment = getTargetData()->
+ getABITypeAlignment(ST->getMemoryVT().getTypeForMVT());
+ unsigned Alignment = ST->getAlignment();
+ if (Alignment >= ABIAlignment) {
+ break;
+ }
+
+ if (LoadSDNode *LD = dyn_cast<LoadSDNode>(ST->getValue())) {
+ if (LD->hasNUsesOfValue(1, 0) && ST->getMemoryVT() == LD->getMemoryVT() &&
+ LD->getAlignment() == Alignment &&
+ !LD->isVolatile() && !LD->isIndexed() &&
+ Chain.reachesChainWithoutSideEffects(SDValue(LD, 1))) {
+ return DAG.getMemmove(Chain, dl, ST->getBasePtr(),
+ LD->getBasePtr(),
+ DAG.getConstant(StoreBits/8, MVT::i32),
+ Alignment, ST->getSrcValue(),
+ ST->getSrcValueOffset(), LD->getSrcValue(),
+ LD->getSrcValueOffset());
+ }
+ }
+ break;
+ }
+ }
+ return SDValue();
+}
+
//===----------------------------------------------------------------------===//
// Addressing mode description hooks
//===----------------------------------------------------------------------===//
bool
XCoreTargetLowering::isLegalAddressingMode(const AddrMode &AM,
const Type *Ty) const {
+ // Be conservative with void
+ // FIXME: Can we be more aggressive?
+ if (Ty->getTypeID() == Type::VoidTyID)
+ return false;
+
const TargetData *TD = TM.getTargetData();
unsigned Size = TD->getTypeAllocSize(Ty);
if (AM.BaseGV) {