From f3c13c82e34b8e90f1080cfe06c6f1328a2d44e1 Mon Sep 17 00:00:00 2001 From: Lauro Ramos Venancio Date: Wed, 1 Aug 2007 19:34:21 +0000 Subject: [PATCH] Expand unaligned loads/stores when the target doesn't support them. (PR1548) git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@40682 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp | 143 ++++++++++++++++++++++- test/CodeGen/ARM/unaligned_load_store.ll | 16 +++ 2 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 test/CodeGen/ARM/unaligned_load_store.ll diff --git a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp index 3ca30dd88d2..b25670c33bf 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -550,6 +550,93 @@ SDOperand ExpandFCOPYSIGNToBitwiseOps(SDNode *Node, MVT::ValueType NVT, return Result; } +/// ExpandUnalignedStore - Expands an unaligned store to 2 half-size stores. +static +SDOperand ExpandUnalignedStore(StoreSDNode *ST, SelectionDAG &DAG, + TargetLowering &TLI) { + assert(MVT::isInteger(ST->getStoredVT()) && + "Non integer unaligned stores not implemented."); + int SVOffset = ST->getSrcValueOffset(); + SDOperand Chain = ST->getChain(); + SDOperand Ptr = ST->getBasePtr(); + SDOperand Val = ST->getValue(); + MVT::ValueType VT = Val.getValueType(); + // Get the half-size VT + MVT::ValueType NewStoredVT = ST->getStoredVT() - 1; + int NumBits = MVT::getSizeInBits(NewStoredVT); + int Alignment = ST->getAlignment(); + 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) { + assert(MVT::isInteger(LD->getLoadedVT()) && + "Non integer unaligned loads not implemented."); + int SVOffset = LD->getSrcValueOffset(); + SDOperand Chain = LD->getChain(); + SDOperand Ptr = LD->getBasePtr(); + MVT::ValueType VT = LD->getValueType(0); + MVT::ValueType NewLoadedVT = LD->getLoadedVT() - 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); +} /// LegalizeOp - We know that the specified value has a legal type, and /// that its operands are legal. Now ensure that the operation itself @@ -1507,7 +1594,22 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) { switch (TLI.getOperationAction(Node->getOpcode(), VT)) { default: assert(0 && "This action is not supported yet!"); - case TargetLowering::Legal: break; + case TargetLowering::Legal: + // If this is an unaligned load and the target doesn't support it, + // expand it. + if (!TLI.allowsUnalignedMemoryAccesses()) { + unsigned ABIAlignment = TLI.getTargetData()-> + getABITypeAlignment(MVT::getTypeForValueType(LD->getLoadedVT())); + if (LD->getAlignment() < ABIAlignment){ + Result = ExpandUnalignedLoad(cast(Result.Val), DAG, + TLI); + Tmp3 = Result.getOperand(0); + Tmp4 = Result.getOperand(1); + LegalizeOp(Tmp3); + LegalizeOp(Tmp4); + } + } + break; case TargetLowering::Custom: Tmp1 = TLI.LowerOperation(Tmp3, DAG); if (Tmp1.Val) { @@ -1561,6 +1663,21 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) { Tmp1 = LegalizeOp(Tmp3); Tmp2 = LegalizeOp(Tmp3.getValue(1)); } + } else { + // If this is an unaligned load and the target doesn't support it, + // expand it. + if (!TLI.allowsUnalignedMemoryAccesses()) { + unsigned ABIAlignment = TLI.getTargetData()-> + getABITypeAlignment(MVT::getTypeForValueType(LD->getLoadedVT())); + if (LD->getAlignment() < ABIAlignment){ + Result = ExpandUnalignedLoad(cast(Result.Val), DAG, + TLI); + Tmp1 = Result.getOperand(0); + Tmp2 = Result.getOperand(1); + LegalizeOp(Tmp1); + LegalizeOp(Tmp2); + } + } } break; case TargetLowering::Expand: @@ -1810,7 +1927,17 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) { MVT::ValueType VT = Tmp3.getValueType(); switch (TLI.getOperationAction(ISD::STORE, VT)) { default: assert(0 && "This action is not supported yet!"); - case TargetLowering::Legal: break; + case TargetLowering::Legal: + // If this is an unaligned store and the target doesn't support it, + // expand it. + if (!TLI.allowsUnalignedMemoryAccesses()) { + unsigned ABIAlignment = TLI.getTargetData()-> + getABITypeAlignment(MVT::getTypeForValueType(ST->getStoredVT())); + if (ST->getAlignment() < ABIAlignment) + Result = ExpandUnalignedStore(cast(Result.Val), DAG, + TLI); + } + break; case TargetLowering::Custom: Tmp1 = TLI.LowerOperation(Result, DAG); if (Tmp1.Val) Result = Tmp1; @@ -1923,7 +2050,17 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) { MVT::ValueType StVT = cast(Result.Val)->getStoredVT(); switch (TLI.getStoreXAction(StVT)) { default: assert(0 && "This action is not supported yet!"); - case TargetLowering::Legal: break; + case TargetLowering::Legal: + // If this is an unaligned store and the target doesn't support it, + // expand it. + if (!TLI.allowsUnalignedMemoryAccesses()) { + unsigned ABIAlignment = TLI.getTargetData()-> + getABITypeAlignment(MVT::getTypeForValueType(ST->getStoredVT())); + if (ST->getAlignment() < ABIAlignment) + Result = ExpandUnalignedStore(cast(Result.Val), DAG, + TLI); + } + break; case TargetLowering::Custom: Tmp1 = TLI.LowerOperation(Result, DAG); if (Tmp1.Val) Result = Tmp1; diff --git a/test/CodeGen/ARM/unaligned_load_store.ll b/test/CodeGen/ARM/unaligned_load_store.ll new file mode 100644 index 00000000000..211d748be34 --- /dev/null +++ b/test/CodeGen/ARM/unaligned_load_store.ll @@ -0,0 +1,16 @@ +; RUN: llvm-as < %s | \ +; RUN: llc -march=arm -o %t -f +; RUN: grep -c ldrb %t | grep 4 +; RUN: grep -c strb %t | grep 4 + + + %struct.p = type <{ i8, i32 }> +@t = global %struct.p <{ i8 1, i32 10 }> ; <%struct.p*> [#uses=1] +@u = weak global %struct.p zeroinitializer ; <%struct.p*> [#uses=1] + +define i32 @main() { +entry: + %tmp3 = load i32* getelementptr (%struct.p* @t, i32 0, i32 1), align 1 ; [#uses=2] + store i32 %tmp3, i32* getelementptr (%struct.p* @u, i32 0, i32 1), align 1 + ret i32 %tmp3 +} -- 2.34.1