+/// ExpandUnalignedStore - Expands an unaligned store to 2 half-size stores.
+static
+SDOperand ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG,
+ TargetLowering &TLI) {
+ SDOperand Chain = ST->getChain();
+ SDOperand Ptr = ST->getBasePtr();
+ SDOperand Val = ST->getValue();
+ MVT::ValueType VT = Val.getValueType();
+ int Alignment = ST->getAlignment();
+ int SVOffset = ST->getSrcValueOffset();
+ if (MVT::isFloatingPoint(ST->getStoredVT())) {
+ // Expand to a bitconvert of the value to the integer type of the
+ // same size, then a (misaligned) int store.
+ MVT::ValueType intVT;
+ if (VT==MVT::f64)
+ intVT = MVT::i64;
+ else if (VT==MVT::f32)
+ intVT = MVT::i32;
+ else
+ assert(0 && "Unaligned load of unsupported floating point type");
+
+ SDOperand Result = DAG.getNode(ISD::BIT_CONVERT, intVT, Val);
+ return DAG.getStore(Chain, Result, Ptr, ST->getSrcValue(),
+ SVOffset, ST->isVolatile(), Alignment);
+ }
+ assert(MVT::isInteger(ST->getStoredVT()) &&
+ "Unaligned store of unknown type.");
+ // Get the half-size VT
+ MVT::ValueType NewStoredVT = ST->getStoredVT() - 1;
+ int NumBits = MVT::getSizeInBits(NewStoredVT);
+ int IncrementSize = NumBits / 8;
+
+ // Divide the stored value in two parts.
+ SDOperand ShiftAmount = DAG.getConstant(NumBits, TLI.getShiftAmountTy());
+ SDOperand Lo = Val;
+ SDOperand Hi = DAG.getNode(ISD::SRL, VT, Val, ShiftAmount);
+
+ // Store the two parts
+ SDOperand Store1, Store2;
+ Store1 = DAG.getTruncStore(Chain, TLI.isLittleEndian()?Lo:Hi, Ptr,
+ ST->getSrcValue(), SVOffset, NewStoredVT,
+ ST->isVolatile(), Alignment);
+ Ptr = DAG.getNode(ISD::ADD, Ptr.getValueType(), Ptr,
+ DAG.getConstant(IncrementSize, TLI.getPointerTy()));
+ Store2 = DAG.getTruncStore(Chain, TLI.isLittleEndian()?Hi:Lo, Ptr,
+ ST->getSrcValue(), SVOffset + IncrementSize,
+ NewStoredVT, ST->isVolatile(), Alignment);
+
+ return DAG.getNode(ISD::TokenFactor, MVT::Other, Store1, Store2);
+}
+
+/// ExpandUnalignedLoad - Expands an unaligned load to 2 half-size loads.
+static
+SDOperand ExpandUnalignedLoad(LoadSDNode *LD, SelectionDAG &DAG,
+ TargetLowering &TLI) {
+ int SVOffset = LD->getSrcValueOffset();
+ SDOperand Chain = LD->getChain();
+ SDOperand Ptr = LD->getBasePtr();
+ MVT::ValueType VT = LD->getValueType(0);
+ MVT::ValueType LoadedVT = LD->getLoadedVT();
+ if (MVT::isFloatingPoint(VT)) {
+ // Expand to a (misaligned) integer load of the same size,
+ // then bitconvert to floating point.
+ MVT::ValueType intVT;
+ if (LoadedVT==MVT::f64)
+ intVT = MVT::i64;
+ else if (LoadedVT==MVT::f32)
+ intVT = MVT::i32;
+ else
+ assert(0 && "Unaligned load of unsupported floating point type");
+
+ SDOperand newLoad = DAG.getLoad(intVT, Chain, Ptr, LD->getSrcValue(),
+ SVOffset, LD->isVolatile(),
+ LD->getAlignment());
+ SDOperand Result = DAG.getNode(ISD::BIT_CONVERT, LoadedVT, newLoad);
+ if (LoadedVT != VT)
+ Result = DAG.getNode(ISD::FP_EXTEND, VT, Result);
+
+ SDOperand Ops[] = { Result, Chain };
+ return DAG.getNode(ISD::MERGE_VALUES, DAG.getVTList(VT, MVT::Other),
+ Ops, 2);
+ }
+ assert(MVT::isInteger(LoadedVT) && "Unaligned load of unsupported type.");
+ MVT::ValueType NewLoadedVT = LoadedVT - 1;
+ int NumBits = MVT::getSizeInBits(NewLoadedVT);
+ int Alignment = LD->getAlignment();
+ int IncrementSize = NumBits / 8;
+ ISD::LoadExtType HiExtType = LD->getExtensionType();
+
+ // If the original load is NON_EXTLOAD, the hi part load must be ZEXTLOAD.
+ if (HiExtType == ISD::NON_EXTLOAD)
+ HiExtType = ISD::ZEXTLOAD;
+
+ // Load the value in two parts
+ SDOperand Lo, Hi;
+ if (TLI.isLittleEndian()) {
+ Lo = DAG.getExtLoad(ISD::ZEXTLOAD, VT, Chain, Ptr, LD->getSrcValue(),
+ SVOffset, NewLoadedVT, LD->isVolatile(), Alignment);
+ Ptr = DAG.getNode(ISD::ADD, Ptr.getValueType(), Ptr,
+ DAG.getConstant(IncrementSize, TLI.getPointerTy()));
+ Hi = DAG.getExtLoad(HiExtType, VT, Chain, Ptr, LD->getSrcValue(),
+ SVOffset + IncrementSize, NewLoadedVT, LD->isVolatile(),
+ Alignment);
+ } else {
+ Hi = DAG.getExtLoad(HiExtType, VT, Chain, Ptr, LD->getSrcValue(), SVOffset,
+ NewLoadedVT,LD->isVolatile(), Alignment);
+ Ptr = DAG.getNode(ISD::ADD, Ptr.getValueType(), Ptr,
+ DAG.getConstant(IncrementSize, TLI.getPointerTy()));
+ Lo = DAG.getExtLoad(ISD::ZEXTLOAD, VT, Chain, Ptr, LD->getSrcValue(),
+ SVOffset + IncrementSize, NewLoadedVT, LD->isVolatile(),
+ Alignment);
+ }
+
+ // aggregate the two parts
+ SDOperand ShiftAmount = DAG.getConstant(NumBits, TLI.getShiftAmountTy());
+ SDOperand Result = DAG.getNode(ISD::SHL, VT, Hi, ShiftAmount);
+ Result = DAG.getNode(ISD::OR, VT, Result, Lo);
+
+ SDOperand TF = DAG.getNode(ISD::TokenFactor, MVT::Other, Lo.getValue(1),
+ Hi.getValue(1));
+
+ SDOperand Ops[] = { Result, TF };
+ return DAG.getNode(ISD::MERGE_VALUES, DAG.getVTList(VT, MVT::Other), Ops, 2);
+}