diff --git a/llvm/include/llvm/IR/RuntimeLibcalls.td b/llvm/include/llvm/IR/RuntimeLibcalls.td index ce7e836f66446..415e20d425e1b 100644 --- a/llvm/include/llvm/IR/RuntimeLibcalls.td +++ b/llvm/include/llvm/IR/RuntimeLibcalls.td @@ -466,6 +466,10 @@ def AEABI_MEMSET8 : RuntimeLibcall; def AEABI_MEMCLR : RuntimeLibcall; def AEABI_MEMCLR4 : RuntimeLibcall; def AEABI_MEMCLR8 : RuntimeLibcall; +def AEABI_UREAD4 : RuntimeLibcall; +def AEABI_UREAD8 : RuntimeLibcall; +def AEABI_UWRITE4 : RuntimeLibcall; +def AEABI_UWRITE8 : RuntimeLibcall; // Hexagon calls def HEXAGON_MEMCPY_LIKELY_ALIGNED_MIN32BYTES_MULT8BYTES : RuntimeLibcall; @@ -1565,6 +1569,13 @@ def __aeabi_ddiv : RuntimeLibcallImpl; // CallingConv::ARM_AAPCS def __aeabi_dmul : RuntimeLibcallImpl; // CallingConv::ARM_AAPCS def __aeabi_dsub : RuntimeLibcallImpl; // CallingConv::ARM_AAPCS +// Unaligned memory access helper functions +// RTABI chapter 5.3.3 +def __aeabi_uread4 : RuntimeLibcallImpl; // CallingConv::ARM_AAPCS +def __aeabi_uread8 : RuntimeLibcallImpl; // CallingConv::ARM_AAPCS +def __aeabi_uwrite4 : RuntimeLibcallImpl; // CallingConv::ARM_AAPCS +def __aeabi_uwrite8 : RuntimeLibcallImpl; // CallingConv::ARM_AAPCS + defvar AEABIOverrides = [ __eqsf2, __eqdf2, __nesf2, __nedf2, @@ -1879,6 +1890,15 @@ def AEABI45MemCalls : LibcallImpls< let CallingConv = ARM_AAPCS; } +// Unaligned Memory read/write operations +// RTABI chapter 5.3.3 +def AEABIUnalignedMemCalls : LibcallImpls< + (add __aeabi_uread4, __aeabi_uread8, + __aeabi_uwrite4, __aeabi_uwrite8), + RuntimeLibcallPredicate<[{hasAEABILibcalls(TT) && isAAPCS_ABI(TT, ABIName)}]>> { + let CallingConv = ARM_AAPCS; +} + def isARMOrThumb : RuntimeLibcallPredicate<"TT.isARM() || TT.isThumb()">; def ARMSystemLibrary @@ -1900,6 +1920,7 @@ def ARMSystemLibrary AEABICalls, AEABI45MemCalls, + AEABIUnalignedMemCalls, ARMLibgccHalfConvertCalls, EABIHalfConvertCalls, GNUEABIHalfConvertCalls, diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp index f28640ce7b107..41c3c7a59911c 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.cpp +++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp @@ -993,6 +993,14 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM_, setIndexedStoreAction(ISD::POST_INC, MVT::i32, Legal); } + // Custom loads/stores to possible use __aeabi_uread/write* + if (Subtarget->isTargetAEABI() && !Subtarget->allowsUnalignedMem()) { + setOperationAction(ISD::STORE, MVT::i32, Custom); + setOperationAction(ISD::STORE, MVT::i64, Custom); + setOperationAction(ISD::LOAD, MVT::i32, Custom); + setOperationAction(ISD::LOAD, MVT::i64, Custom); + } + setOperationAction(ISD::SADDO, MVT::i32, Custom); setOperationAction(ISD::UADDO, MVT::i32, Custom); setOperationAction(ISD::SSUBO, MVT::i32, Custom); @@ -10012,6 +10020,95 @@ void ARMTargetLowering::ExpandDIV_Windows( Results.push_back(DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lower, Upper)); } +std::pair +ARMTargetLowering::LowerAEABIUnalignedLoad(SDValue Op, + SelectionDAG &DAG) const { + // If we have an unaligned load from a i32 or i64 that would normally be + // split into separate ldrb's, we can use the __aeabi_uread4/__aeabi_uread8 + // functions instead. + LoadSDNode *LD = cast(Op.getNode()); + EVT MemVT = LD->getMemoryVT(); + if (MemVT != MVT::i32 && MemVT != MVT::i64) + return std::make_pair(SDValue(), SDValue()); + + const auto &MF = DAG.getMachineFunction(); + unsigned AS = LD->getAddressSpace(); + Align Alignment = LD->getAlign(); + const DataLayout &DL = DAG.getDataLayout(); + bool AllowsUnaligned = Subtarget->allowsUnalignedMem(); + + if (MF.getFunction().hasMinSize() && !AllowsUnaligned && + Alignment <= llvm::Align(2)) { + + RTLIB::Libcall LC = + (MemVT == MVT::i32) ? RTLIB::AEABI_UREAD4 : RTLIB::AEABI_UREAD8; + + MakeLibCallOptions Opts; + SDLoc dl(Op); + + auto Pair = makeLibCall(DAG, LC, MemVT.getSimpleVT(), LD->getBasePtr(), + Opts, dl, LD->getChain()); + + // If necessary, extend the node to 64bit + if (LD->getExtensionType() != ISD::NON_EXTLOAD) { + unsigned ExtType = LD->getExtensionType() == ISD::SEXTLOAD + ? ISD::SIGN_EXTEND + : ISD::ZERO_EXTEND; + SDValue EN = DAG.getNode(ExtType, dl, LD->getValueType(0), Pair.first); + Pair.first = EN; + } + return Pair; + } + + // Default expand to individual loads + if (!allowsMemoryAccess(*DAG.getContext(), DL, MemVT, AS, Alignment)) + return expandUnalignedLoad(LD, DAG); + return std::make_pair(SDValue(), SDValue()); +} + +SDValue ARMTargetLowering::LowerAEABIUnalignedStore(SDValue Op, + SelectionDAG &DAG) const { + // If we have an unaligned store to a i32 or i64 that would normally be + // split into separate ldrb's, we can use the __aeabi_uwrite4/__aeabi_uwrite8 + // functions instead. + StoreSDNode *ST = cast(Op.getNode()); + EVT MemVT = ST->getMemoryVT(); + if (MemVT != MVT::i32 && MemVT != MVT::i64) + return SDValue(); + + const auto &MF = DAG.getMachineFunction(); + unsigned AS = ST->getAddressSpace(); + Align Alignment = ST->getAlign(); + const DataLayout &DL = DAG.getDataLayout(); + bool AllowsUnaligned = Subtarget->allowsUnalignedMem(); + + if (MF.getFunction().hasMinSize() && !AllowsUnaligned && + Alignment <= llvm::Align(2)) { + + SDLoc dl(Op); + + // If necessary, trunc the value to 32bit + SDValue StoreVal = ST->getOperand(1); + if (ST->isTruncatingStore()) + StoreVal = DAG.getNode(ISD::TRUNCATE, dl, MemVT, ST->getOperand(1)); + + RTLIB::Libcall LC = + (MemVT == MVT::i32) ? RTLIB::AEABI_UWRITE4 : RTLIB::AEABI_UWRITE8; + + MakeLibCallOptions Opts; + auto CallResult = + makeLibCall(DAG, LC, MVT::isVoid, {StoreVal, ST->getBasePtr()}, Opts, + dl, ST->getChain()); + + return CallResult.second; + } + + // Default expand to individual stores + if (!allowsMemoryAccess(*DAG.getContext(), DL, MemVT, AS, Alignment)) + return expandUnalignedStore(ST, DAG); + return SDValue(); +} + static SDValue LowerPredicateLoad(SDValue Op, SelectionDAG &DAG) { LoadSDNode *LD = cast(Op.getNode()); EVT MemVT = LD->getMemoryVT(); @@ -10054,11 +10151,11 @@ void ARMTargetLowering::LowerLOAD(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const { LoadSDNode *LD = cast(N); EVT MemVT = LD->getMemoryVT(); - assert(LD->isUnindexed() && "Loads should be unindexed at this point."); if (MemVT == MVT::i64 && Subtarget->hasV5TEOps() && !Subtarget->isThumb1Only() && LD->isVolatile() && LD->getAlign() >= Subtarget->getDualLoadStoreAlignment()) { + assert(LD->isUnindexed() && "Loads should be unindexed at this point."); SDLoc dl(N); SDValue Result = DAG.getMemIntrinsicNode( ARMISD::LDRD, dl, DAG.getVTList({MVT::i32, MVT::i32, MVT::Other}), @@ -10067,6 +10164,12 @@ void ARMTargetLowering::LowerLOAD(SDNode *N, SmallVectorImpl &Results, SDValue Hi = Result.getValue(DAG.getDataLayout().isLittleEndian() ? 1 : 0); SDValue Pair = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, Lo, Hi); Results.append({Pair, Result.getValue(2)}); + } else if (MemVT == MVT::i32 || MemVT == MVT::i64) { + auto Pair = LowerAEABIUnalignedLoad(SDValue(N, 0), DAG); + if (Pair.first) { + Results.push_back(Pair.first); + Results.push_back(Pair.second); + } } } @@ -10108,15 +10211,15 @@ static SDValue LowerPredicateStore(SDValue Op, SelectionDAG &DAG) { ST->getMemOperand()); } -static SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG, - const ARMSubtarget *Subtarget) { +SDValue ARMTargetLowering::LowerSTORE(SDValue Op, SelectionDAG &DAG, + const ARMSubtarget *Subtarget) const { StoreSDNode *ST = cast(Op.getNode()); EVT MemVT = ST->getMemoryVT(); - assert(ST->isUnindexed() && "Stores should be unindexed at this point."); if (MemVT == MVT::i64 && Subtarget->hasV5TEOps() && !Subtarget->isThumb1Only() && ST->isVolatile() && ST->getAlign() >= Subtarget->getDualLoadStoreAlignment()) { + assert(ST->isUnindexed() && "Stores should be unindexed at this point."); SDNode *N = Op.getNode(); SDLoc dl(N); @@ -10136,8 +10239,9 @@ static SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG, ((MemVT == MVT::v2i1 || MemVT == MVT::v4i1 || MemVT == MVT::v8i1 || MemVT == MVT::v16i1))) { return LowerPredicateStore(Op, DAG); + } else if (MemVT == MVT::i32 || MemVT == MVT::i64) { + return LowerAEABIUnalignedStore(Op, DAG); } - return SDValue(); } @@ -10669,8 +10773,19 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::UADDSAT: case ISD::USUBSAT: return LowerADDSUBSAT(Op, DAG, Subtarget); - case ISD::LOAD: - return LowerPredicateLoad(Op, DAG); + case ISD::LOAD: { + auto *LD = cast(Op); + EVT MemVT = LD->getMemoryVT(); + if (Subtarget->hasMVEIntegerOps() && + (MemVT == MVT::v2i1 || MemVT == MVT::v4i1 || MemVT == MVT::v8i1 || + MemVT == MVT::v16i1)) + return LowerPredicateLoad(Op, DAG); + + auto Pair = LowerAEABIUnalignedLoad(Op, DAG); + if (Pair.first) + return DAG.getMergeValues({Pair.first, Pair.second}, SDLoc(Pair.first)); + return SDValue(); + } case ISD::STORE: return LowerSTORE(Op, DAG, Subtarget); case ISD::MLOAD: @@ -10811,6 +10926,9 @@ void ARMTargetLowering::ReplaceNodeResults(SDNode *N, case ISD::LOAD: LowerLOAD(N, Results, DAG); break; + case ISD::STORE: + Res = LowerAEABIUnalignedStore(SDValue(N, 0), DAG); + break; case ISD::TRUNCATE: Res = LowerTruncate(N, DAG, Subtarget); break; @@ -19859,31 +19977,45 @@ ARMTargetLowering::getPreIndexedAddressParts(SDNode *N, SDValue &Base, EVT VT; SDValue Ptr; Align Alignment; + unsigned AS = 0; bool isSEXTLoad = false; bool IsMasked = false; if (LoadSDNode *LD = dyn_cast(N)) { Ptr = LD->getBasePtr(); VT = LD->getMemoryVT(); Alignment = LD->getAlign(); + AS = LD->getAddressSpace(); isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD; } else if (StoreSDNode *ST = dyn_cast(N)) { Ptr = ST->getBasePtr(); VT = ST->getMemoryVT(); Alignment = ST->getAlign(); + AS = ST->getAddressSpace(); } else if (MaskedLoadSDNode *LD = dyn_cast(N)) { Ptr = LD->getBasePtr(); VT = LD->getMemoryVT(); Alignment = LD->getAlign(); + AS = LD->getAddressSpace(); isSEXTLoad = LD->getExtensionType() == ISD::SEXTLOAD; IsMasked = true; } else if (MaskedStoreSDNode *ST = dyn_cast(N)) { Ptr = ST->getBasePtr(); VT = ST->getMemoryVT(); Alignment = ST->getAlign(); + AS = ST->getAddressSpace(); IsMasked = true; } else return false; + unsigned Fast = 0; + if (!allowsMisalignedMemoryAccesses(VT, AS, Alignment, + MachineMemOperand::MONone, &Fast)) { + // Only generate post-increment or pre-increment forms when a real + // hardware instruction exists for them. Do not emit postinc/preinc + // if the operation will end up as a libcall. + return false; + } + bool isInc; bool isLegal = false; if (VT.isVector()) diff --git a/llvm/lib/Target/ARM/ARMISelLowering.h b/llvm/lib/Target/ARM/ARMISelLowering.h index bc2fec3c1bdb5..ae93fdf6d619b 100644 --- a/llvm/lib/Target/ARM/ARMISelLowering.h +++ b/llvm/lib/Target/ARM/ARMISelLowering.h @@ -919,10 +919,14 @@ class VectorType; SDValue LowerSPONENTRY(SDValue Op, SelectionDAG &DAG) const; void LowerLOAD(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const; + SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG, + const ARMSubtarget *Subtarget) const; + std::pair + LowerAEABIUnalignedLoad(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerAEABIUnalignedStore(SDValue Op, SelectionDAG &DAG) const; SDValue LowerFP_TO_BF16(SDValue Op, SelectionDAG &DAG) const; SDValue LowerCMP(SDValue Op, SelectionDAG &DAG) const; SDValue LowerABS(SDValue Op, SelectionDAG &DAG) const; - Register getRegisterByName(const char* RegName, LLT VT, const MachineFunction &MF) const override; diff --git a/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll b/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll index ca5fd2bc14f40..125326fd754fa 100644 --- a/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll +++ b/llvm/test/CodeGen/ARM/i64_volatile_load_store.ll @@ -121,23 +121,22 @@ define void @test_unaligned() { ; CHECK-ARMV5TE-NEXT: push {r4, r5, r6, lr} ; CHECK-ARMV5TE-NEXT: ldr r0, .LCPI1_0 ; CHECK-ARMV5TE-NEXT: ldr r6, .LCPI1_1 -; CHECK-ARMV5TE-NEXT: mov r1, r0 -; CHECK-ARMV5TE-NEXT: ldrb lr, [r1, #4]! -; CHECK-ARMV5TE-NEXT: ldrb r3, [r1, #2] -; CHECK-ARMV5TE-NEXT: ldrb r12, [r1, #3] -; CHECK-ARMV5TE-NEXT: ldrb r1, [r0] -; CHECK-ARMV5TE-NEXT: ldrb r2, [r0, #1] -; CHECK-ARMV5TE-NEXT: ldrb r4, [r0, #2] -; CHECK-ARMV5TE-NEXT: ldrb r5, [r0, #3] -; CHECK-ARMV5TE-NEXT: ldrb r0, [r0, #5] -; CHECK-ARMV5TE-NEXT: strb r0, [r6, #5] -; CHECK-ARMV5TE-NEXT: strb r4, [r6, #2] -; CHECK-ARMV5TE-NEXT: strb r5, [r6, #3] -; CHECK-ARMV5TE-NEXT: strb r1, [r6] -; CHECK-ARMV5TE-NEXT: strb r2, [r6, #1] -; CHECK-ARMV5TE-NEXT: strb lr, [r6, #4]! +; CHECK-ARMV5TE-NEXT: ldrb r12, [r0] +; CHECK-ARMV5TE-NEXT: ldrb lr, [r0, #1] +; CHECK-ARMV5TE-NEXT: ldrb r3, [r0, #2] +; CHECK-ARMV5TE-NEXT: ldrb r1, [r0, #3] +; CHECK-ARMV5TE-NEXT: ldrb r2, [r0, #5] +; CHECK-ARMV5TE-NEXT: ldrb r4, [r0, #4] +; CHECK-ARMV5TE-NEXT: ldrb r5, [r0, #7] +; CHECK-ARMV5TE-NEXT: ldrb r0, [r0, #6] +; CHECK-ARMV5TE-NEXT: strb r0, [r6, #6] +; CHECK-ARMV5TE-NEXT: strb r5, [r6, #7] +; CHECK-ARMV5TE-NEXT: strb r4, [r6, #4] +; CHECK-ARMV5TE-NEXT: strb r2, [r6, #5] ; CHECK-ARMV5TE-NEXT: strb r3, [r6, #2] -; CHECK-ARMV5TE-NEXT: strb r12, [r6, #3] +; CHECK-ARMV5TE-NEXT: strb r1, [r6, #3] +; CHECK-ARMV5TE-NEXT: strb r12, [r6] +; CHECK-ARMV5TE-NEXT: strb lr, [r6, #1] ; CHECK-ARMV5TE-NEXT: pop {r4, r5, r6, pc} ; CHECK-ARMV5TE-NEXT: .p2align 2 ; CHECK-ARMV5TE-NEXT: @ %bb.1: @@ -164,23 +163,22 @@ define void @test_unaligned() { ; CHECK-ARMV4T-NEXT: push {r4, r5, r6, lr} ; CHECK-ARMV4T-NEXT: ldr r0, .LCPI1_0 ; CHECK-ARMV4T-NEXT: ldr r6, .LCPI1_1 -; CHECK-ARMV4T-NEXT: mov r1, r0 -; CHECK-ARMV4T-NEXT: ldrb lr, [r1, #4]! -; CHECK-ARMV4T-NEXT: ldrb r3, [r1, #2] -; CHECK-ARMV4T-NEXT: ldrb r12, [r1, #3] -; CHECK-ARMV4T-NEXT: ldrb r1, [r0] -; CHECK-ARMV4T-NEXT: ldrb r2, [r0, #1] -; CHECK-ARMV4T-NEXT: ldrb r4, [r0, #2] -; CHECK-ARMV4T-NEXT: ldrb r5, [r0, #3] -; CHECK-ARMV4T-NEXT: ldrb r0, [r0, #5] -; CHECK-ARMV4T-NEXT: strb r0, [r6, #5] -; CHECK-ARMV4T-NEXT: strb r4, [r6, #2] -; CHECK-ARMV4T-NEXT: strb r5, [r6, #3] -; CHECK-ARMV4T-NEXT: strb r1, [r6] -; CHECK-ARMV4T-NEXT: strb r2, [r6, #1] -; CHECK-ARMV4T-NEXT: strb lr, [r6, #4]! +; CHECK-ARMV4T-NEXT: ldrb r12, [r0] +; CHECK-ARMV4T-NEXT: ldrb lr, [r0, #1] +; CHECK-ARMV4T-NEXT: ldrb r3, [r0, #2] +; CHECK-ARMV4T-NEXT: ldrb r1, [r0, #3] +; CHECK-ARMV4T-NEXT: ldrb r2, [r0, #5] +; CHECK-ARMV4T-NEXT: ldrb r4, [r0, #4] +; CHECK-ARMV4T-NEXT: ldrb r5, [r0, #7] +; CHECK-ARMV4T-NEXT: ldrb r0, [r0, #6] +; CHECK-ARMV4T-NEXT: strb r0, [r6, #6] +; CHECK-ARMV4T-NEXT: strb r5, [r6, #7] +; CHECK-ARMV4T-NEXT: strb r4, [r6, #4] +; CHECK-ARMV4T-NEXT: strb r2, [r6, #5] ; CHECK-ARMV4T-NEXT: strb r3, [r6, #2] -; CHECK-ARMV4T-NEXT: strb r12, [r6, #3] +; CHECK-ARMV4T-NEXT: strb r1, [r6, #3] +; CHECK-ARMV4T-NEXT: strb r12, [r6] +; CHECK-ARMV4T-NEXT: strb lr, [r6, #1] ; CHECK-ARMV4T-NEXT: pop {r4, r5, r6, lr} ; CHECK-ARMV4T-NEXT: bx lr ; CHECK-ARMV4T-NEXT: .p2align 2 @@ -210,23 +208,22 @@ define void @test_unaligned() { ; CHECK-ARMV7-STRICT-NEXT: movw r6, :lower16:y_unaligned ; CHECK-ARMV7-STRICT-NEXT: movt r0, :upper16:x_unaligned ; CHECK-ARMV7-STRICT-NEXT: movt r6, :upper16:y_unaligned -; CHECK-ARMV7-STRICT-NEXT: mov r1, r0 -; CHECK-ARMV7-STRICT-NEXT: ldrb r12, [r1, #4]! -; CHECK-ARMV7-STRICT-NEXT: ldrb r3, [r0] +; CHECK-ARMV7-STRICT-NEXT: ldrb r12, [r0] ; CHECK-ARMV7-STRICT-NEXT: ldrb lr, [r0, #1] -; CHECK-ARMV7-STRICT-NEXT: ldrb r2, [r0, #2] -; CHECK-ARMV7-STRICT-NEXT: ldrb r4, [r0, #3] -; CHECK-ARMV7-STRICT-NEXT: ldrb r0, [r0, #5] -; CHECK-ARMV7-STRICT-NEXT: ldrb r5, [r1, #2] -; CHECK-ARMV7-STRICT-NEXT: ldrb r1, [r1, #3] -; CHECK-ARMV7-STRICT-NEXT: strb r0, [r6, #5] -; CHECK-ARMV7-STRICT-NEXT: strb r2, [r6, #2] -; CHECK-ARMV7-STRICT-NEXT: strb r4, [r6, #3] -; CHECK-ARMV7-STRICT-NEXT: strb r3, [r6] -; CHECK-ARMV7-STRICT-NEXT: strb lr, [r6, #1] -; CHECK-ARMV7-STRICT-NEXT: strb r12, [r6, #4]! -; CHECK-ARMV7-STRICT-NEXT: strb r5, [r6, #2] +; CHECK-ARMV7-STRICT-NEXT: ldrb r3, [r0, #2] +; CHECK-ARMV7-STRICT-NEXT: ldrb r1, [r0, #3] +; CHECK-ARMV7-STRICT-NEXT: ldrb r2, [r0, #5] +; CHECK-ARMV7-STRICT-NEXT: ldrb r4, [r0, #4] +; CHECK-ARMV7-STRICT-NEXT: ldrb r5, [r0, #7] +; CHECK-ARMV7-STRICT-NEXT: ldrb r0, [r0, #6] +; CHECK-ARMV7-STRICT-NEXT: strb r0, [r6, #6] +; CHECK-ARMV7-STRICT-NEXT: strb r5, [r6, #7] +; CHECK-ARMV7-STRICT-NEXT: strb r4, [r6, #4] +; CHECK-ARMV7-STRICT-NEXT: strb r2, [r6, #5] +; CHECK-ARMV7-STRICT-NEXT: strb r3, [r6, #2] ; CHECK-ARMV7-STRICT-NEXT: strb r1, [r6, #3] +; CHECK-ARMV7-STRICT-NEXT: strb r12, [r6] +; CHECK-ARMV7-STRICT-NEXT: strb lr, [r6, #1] ; CHECK-ARMV7-STRICT-NEXT: pop {r4, r5, r6, pc} ; ; CHECK-ARMV6-LABEL: test_unaligned: @@ -251,23 +248,22 @@ define void @test_unaligned() { ; CHECK-ARMV6-STRICT-NEXT: push {r4, r5, r6, lr} ; CHECK-ARMV6-STRICT-NEXT: ldr r0, .LCPI1_0 ; CHECK-ARMV6-STRICT-NEXT: ldr r6, .LCPI1_1 -; CHECK-ARMV6-STRICT-NEXT: mov r1, r0 -; CHECK-ARMV6-STRICT-NEXT: ldrb lr, [r1, #4]! -; CHECK-ARMV6-STRICT-NEXT: ldrb r3, [r1, #2] -; CHECK-ARMV6-STRICT-NEXT: ldrb r12, [r1, #3] -; CHECK-ARMV6-STRICT-NEXT: ldrb r1, [r0] -; CHECK-ARMV6-STRICT-NEXT: ldrb r2, [r0, #1] -; CHECK-ARMV6-STRICT-NEXT: ldrb r4, [r0, #2] -; CHECK-ARMV6-STRICT-NEXT: ldrb r5, [r0, #3] -; CHECK-ARMV6-STRICT-NEXT: ldrb r0, [r0, #5] -; CHECK-ARMV6-STRICT-NEXT: strb r0, [r6, #5] -; CHECK-ARMV6-STRICT-NEXT: strb r4, [r6, #2] -; CHECK-ARMV6-STRICT-NEXT: strb r5, [r6, #3] -; CHECK-ARMV6-STRICT-NEXT: strb r1, [r6] -; CHECK-ARMV6-STRICT-NEXT: strb r2, [r6, #1] -; CHECK-ARMV6-STRICT-NEXT: strb lr, [r6, #4]! +; CHECK-ARMV6-STRICT-NEXT: ldrb r12, [r0] +; CHECK-ARMV6-STRICT-NEXT: ldrb lr, [r0, #1] +; CHECK-ARMV6-STRICT-NEXT: ldrb r3, [r0, #2] +; CHECK-ARMV6-STRICT-NEXT: ldrb r1, [r0, #3] +; CHECK-ARMV6-STRICT-NEXT: ldrb r2, [r0, #5] +; CHECK-ARMV6-STRICT-NEXT: ldrb r4, [r0, #4] +; CHECK-ARMV6-STRICT-NEXT: ldrb r5, [r0, #7] +; CHECK-ARMV6-STRICT-NEXT: ldrb r0, [r0, #6] +; CHECK-ARMV6-STRICT-NEXT: strb r0, [r6, #6] +; CHECK-ARMV6-STRICT-NEXT: strb r5, [r6, #7] +; CHECK-ARMV6-STRICT-NEXT: strb r4, [r6, #4] +; CHECK-ARMV6-STRICT-NEXT: strb r2, [r6, #5] ; CHECK-ARMV6-STRICT-NEXT: strb r3, [r6, #2] -; CHECK-ARMV6-STRICT-NEXT: strb r12, [r6, #3] +; CHECK-ARMV6-STRICT-NEXT: strb r1, [r6, #3] +; CHECK-ARMV6-STRICT-NEXT: strb r12, [r6] +; CHECK-ARMV6-STRICT-NEXT: strb lr, [r6, #1] ; CHECK-ARMV6-STRICT-NEXT: pop {r4, r5, r6, pc} ; CHECK-ARMV6-STRICT-NEXT: .p2align 2 ; CHECK-ARMV6-STRICT-NEXT: @ %bb.1: diff --git a/llvm/test/CodeGen/ARM/unaligned_load_store_aeabi.ll b/llvm/test/CodeGen/ARM/unaligned_load_store_aeabi.ll new file mode 100644 index 0000000000000..5e395c49cd3b2 --- /dev/null +++ b/llvm/test/CodeGen/ARM/unaligned_load_store_aeabi.ll @@ -0,0 +1,728 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=thumbv6m-eabi -mattr=+strict-align %s -o - | FileCheck %s -check-prefix=CHECK-V6M-MINSIZE +; RUN: llc -mtriple=thumbv6m-eabi -mattr=+strict-align %s -o - | FileCheck %s -check-prefix=CHECK-V6M-OPTSIZE +; RUN: llc -mtriple=thumbv7m-eabi -mattr=+strict-align %s -o - | FileCheck %s -check-prefix=CHECK-V7M-MINSIZE +; RUN: llc -mtriple=thumbv7m-eabi -mattr=+strict-align %s -o - | FileCheck %s -check-prefix=CHECK-V7M-OPTSIZE +; RUN: llc -mtriple=thumbv7m-eabi -mattr=-strict-align %s -o - | FileCheck %s -check-prefix=CHECK-ALIGNED-MINSIZE +; RUN: llc -mtriple=thumbv7m-eabi -mattr=-strict-align %s -o - | FileCheck %s -check-prefix=CHECK-ALIGNED-OPTSIZE + +define void @loadstore4_align1_minsize(i32* %a, i32* %b) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: loadstore4_align1_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: mov r4, r1 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V6M-MINSIZE-NEXT: mov r1, r4 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uwrite4 +; CHECK-V6M-MINSIZE-NEXT: pop {r4, pc} +; +; CHECK-V7M-MINSIZE-LABEL: loadstore4_align1_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: mov r4, r1 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V7M-MINSIZE-NEXT: mov r1, r4 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uwrite4 +; CHECK-V7M-MINSIZE-NEXT: pop {r4, pc} +; +; CHECK-ALIGNED-MINSIZE-LABEL: loadstore4_align1_minsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: str r0, [r1] +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 1 + store i32 %tmp, i32* %b, align 1 + ret void +} + +define void @loadstore4_align1_optsize(i32* %a, i32* %b) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: loadstore4_align1_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE: .save {r4, lr} +; CHECK-V6M-OPTSIZE: push {r4, lr} +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uwrite4 +; CHECK-V6M-OPTSIZE: pop {r4, pc} +; +; CHECK-V7M-OPTSIZE-LABEL: loadstore4_align1_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uwrite4 +; CHECK-V7M-OPTSIZE: bx lr +; +; CHECK-ALIGNED-OPTSIZE-LABEL: loadstore4_align1_optsize: +; CHECK-ALIGNED-OPTSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-OPTSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-OPTSIZE-NEXT: str r0, [r1] +; CHECK-ALIGNED-OPTSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 1 + store i32 %tmp, i32* %b, align 1 + ret void +} + +define i32 @load4_align1_minsize(i32* %a) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: load4_align1_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: load4_align1_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-ALIGNED-MINSIZE-LABEL: load4_align1_minsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 1 + ret i32 %tmp +} + +define i32 @load4_align1_optsize(i32* %a) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: load4_align1_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: load4_align1_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V7M-OPTSIZE: bx lr +; +; CHECK-ALIGNED-OPTSIZE-LABEL: load4_align1_optsize: +; CHECK-ALIGNED-OPTSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-OPTSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-OPTSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 1 + ret i32 %tmp +} + +define i64 @load4_align1_zext_minsize(i32* %a) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: load4_align1_zext_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V6M-MINSIZE-NEXT: movs r1, #0 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: load4_align1_zext_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V7M-MINSIZE-NEXT: movs r1, #0 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-ALIGNED-MINSIZE-LABEL: load4_align1_zext_minsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: movs r1, #0 +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 1 + %ext = zext i32 %tmp to i64 + ret i64 %ext +} + +define i64 @load4_align1_zext_optsize(i32* %a) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: load4_align1_zext_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: load4_align1_zext_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V7M-OPTSIZE: bx lr +; +; CHECK-ALIGNED-OPTSIZE-LABEL: load4_align1_zext_optsize: +; CHECK-ALIGNED-OPTSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-OPTSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-OPTSIZE-NEXT: movs r1, #0 +; CHECK-ALIGNED-OPTSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 1 + %ext = zext i32 %tmp to i64 + ret i64 %ext +} + +define i64 @load4_align1_sext_minsize(i32* %a) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: load4_align1_sext_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V6M-MINSIZE-NEXT: asrs r1, r0, #31 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: load4_align1_sext_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V7M-MINSIZE-NEXT: asrs r1, r0, #31 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-ALIGNED-MINSIZE-LABEL: load4_align1_sext_minsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: asrs r1, r0, #31 +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 1 + %ext = sext i32 %tmp to i64 + ret i64 %ext +} + +define i64 @load4_align1_sext_optsize(i32* %a) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: load4_align1_sext_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: load4_align1_sext_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V7M-OPTSIZE: bx lr +; +; CHECK-ALIGNED-OPTSIZE-LABEL: load4_align1_sext_optsize: +; CHECK-ALIGNED-OPTSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-OPTSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-OPTSIZE-NEXT: asrs r1, r0, #31 +; CHECK-ALIGNED-OPTSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 1 + %ext = sext i32 %tmp to i64 + ret i64 %ext +} + +define void @store4_align1_minsize(i32* %a, i32 %b) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: store4_align1_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: mov r2, r0 +; CHECK-V6M-MINSIZE-NEXT: mov r0, r1 +; CHECK-V6M-MINSIZE-NEXT: mov r1, r2 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uwrite4 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: store4_align1_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: mov r2, r0 +; CHECK-V7M-MINSIZE-NEXT: mov r0, r1 +; CHECK-V7M-MINSIZE-NEXT: mov r1, r2 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uwrite4 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-ALIGNED-MINSIZE-LABEL: store4_align1_minsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: str r1, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + store i32 %b, i32* %a, align 1 + ret void +} + +define void @store4_align1_optsize(i32* %a, i32 %b) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: store4_align1_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uwrite4 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: store4_align1_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uwrite4 +; CHECK-V7M-OPTSIZE: bx lr +; +; CHECK-ALIGNED-OPTSIZE-LABEL: store4_align1_optsize: +; CHECK-ALIGNED-OPTSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-OPTSIZE-NEXT: str r1, [r0] +; CHECK-ALIGNED-OPTSIZE-NEXT: bx lr +entry: + store i32 %b, i32* %a, align 1 + ret void +} + +define i32 @load4_align2_minsize(i32* %a) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: load4_align2_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: load4_align2_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-ALIGNED-MINSIZE-LABEL: load4_align2_minsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 2 + ret i32 %tmp +} + +define i32 @load4_align2_optsize(i32* %a) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: load4_align2_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: load4_align2_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V7M-OPTSIZE: bx lr +; +; CHECK-ALIGNED-OPTSIZE-LABEL: load4_align2_optsize: +; CHECK-ALIGNED-OPTSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-OPTSIZE-NEXT: ldr r0, [r0] +; CHECK-ALIGNED-OPTSIZE-NEXT: bx lr +entry: + %tmp = load i32, i32* %a, align 2 + ret i32 %tmp +} + +define i64 @load6_align1_zext_minsize(i48* %a) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: load6_align1_zext_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: ldrb r1, [r0, #4] +; CHECK-V6M-MINSIZE-NEXT: ldrb r2, [r0, #5] +; CHECK-V6M-MINSIZE-NEXT: lsls r2, r2, #8 +; CHECK-V6M-MINSIZE-NEXT: adds r4, r2, r1 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V6M-MINSIZE-NEXT: mov r1, r4 +; CHECK-V6M-MINSIZE-NEXT: pop {r4, pc} +; +; CHECK-V7M-MINSIZE-LABEL: load6_align1_zext_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: mov r4, r0 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V7M-MINSIZE-NEXT: ldrb r2, [r4, #5] +; CHECK-V7M-MINSIZE-NEXT: ldrb r1, [r4, #4] +; CHECK-V7M-MINSIZE-NEXT: orr.w r1, r1, r2, lsl #8 +; CHECK-V7M-MINSIZE-NEXT: pop {r4, pc} +; +; CHECK-ALIGNED-MINSIZE-LABEL: load6_align1_zext_minsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: ldr r2, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: ldrh r1, [r0, #4] +; CHECK-ALIGNED-MINSIZE-NEXT: mov r0, r2 +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + %tmp = load i48, i48* %a, align 1 + %ext = zext i48 %tmp to i64 + ret i64 %ext +} + +define i64 @load6_align1_zext_optsize(i48* %a) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: load6_align1_zext_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: load6_align1_zext_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V7M-OPTSIZE: bx lr +; +; CHECK-ALIGNED-MINSIZE-LABEL: load6_align1_zext_optsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: ldr r2, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: ldrh r1, [r0, #4] +; CHECK-ALIGNED-MINSIZE-NEXT: mov r0, r2 +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + %tmp = load i48, i48* %a, align 1 + %ext = zext i48 %tmp to i64 + ret i64 %ext +} + +define i64 @load6_align1_sext_minsize(i48* %a) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: load6_align1_sext_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: movs r1, #5 +; CHECK-V6M-MINSIZE-NEXT: ldrsb r1, [r0, r1] +; CHECK-V6M-MINSIZE-NEXT: lsls r1, r1, #8 +; CHECK-V6M-MINSIZE-NEXT: ldrb r2, [r0, #4] +; CHECK-V6M-MINSIZE-NEXT: adds r4, r1, r2 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V6M-MINSIZE-NEXT: mov r1, r4 +; CHECK-V6M-MINSIZE-NEXT: pop {r4, pc} +; +; CHECK-V7M-MINSIZE-LABEL: load6_align1_sext_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: ldrsb.w r1, [r0, #5] +; CHECK-V7M-MINSIZE-NEXT: ldrb r2, [r0, #4] +; CHECK-V7M-MINSIZE-NEXT: orr.w r4, r2, r1, lsl #8 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread4 +; CHECK-V7M-MINSIZE-NEXT: mov r1, r4 +; CHECK-V7M-MINSIZE-NEXT: pop {r4, pc} +; +; CHECK-ALIGNED-MINSIZE-LABEL: load6_align1_sext_minsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: ldr r2, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: ldrsh.w r1, [r0, #4] +; CHECK-ALIGNED-MINSIZE-NEXT: mov r0, r2 +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + %tmp = load i48, i48* %a, align 1 + %ext = sext i48 %tmp to i64 + ret i64 %ext +} + +define i64 @load6_align1_sext_optsize(i48* %a) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: load6_align1_sext_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: load6_align1_sext_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread4 +; CHECK-V7M-OPTSIZE: bx lr +; +; CHECK-ALIGNED-OPTSIZE-LABEL: load6_align1_sext_optsize: +; CHECK-ALIGNED-OPTSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-OPTSIZE-NEXT: ldr r2, [r0] +; CHECK-ALIGNED-OPTSIZE-NEXT: ldrsh.w r1, [r0, #4] +; CHECK-ALIGNED-OPTSIZE-NEXT: mov r0, r2 +; CHECK-ALIGNED-OPTSIZE-NEXT: bx lr +entry: + %tmp = load i48, i48* %a, align 1 + %ext = sext i48 %tmp to i64 + ret i64 %ext +} + +define void @store6_align1_minsize(i48* %a, i48 %b) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: store6_align1_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: mov r1, r0 +; CHECK-V6M-MINSIZE-NEXT: strb r3, [r0, #4] +; CHECK-V6M-MINSIZE-NEXT: lsrs r0, r3, #8 +; CHECK-V6M-MINSIZE-NEXT: strb r0, [r1, #5] +; CHECK-V6M-MINSIZE-NEXT: mov r0, r2 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uwrite4 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: store6_align1_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: mov r1, r0 +; CHECK-V7M-MINSIZE-NEXT: strb r3, [r0, #4] +; CHECK-V7M-MINSIZE-NEXT: lsrs r0, r3, #8 +; CHECK-V7M-MINSIZE-NEXT: strb r0, [r1, #5] +; CHECK-V7M-MINSIZE-NEXT: mov r0, r2 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uwrite4 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-ALIGNED-MINSIZE-LABEL: store6_align1_minsize: +; CHECK-ALIGNED-MINSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-MINSIZE-NEXT: strh r3, [r0, #4] +; CHECK-ALIGNED-MINSIZE-NEXT: str r2, [r0] +; CHECK-ALIGNED-MINSIZE-NEXT: bx lr +entry: + store i48 %b, i48* %a, align 1 + ret void +} + +define void @store6_align1_optsize(i48* %a, i48 %b) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: store6_align1_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uwrite4 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: store6_align1_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uwrite4 +; CHECK-V7M-OPTSIZE: bx lr +; +; CHECK-ALIGNED-OPTSIZE-LABEL: store6_align1_optsize: +; CHECK-ALIGNED-OPTSIZE: @ %bb.0: @ %entry +; CHECK-ALIGNED-OPTSIZE-NEXT: strh r3, [r0, #4] +; CHECK-ALIGNED-OPTSIZE-NEXT: str r2, [r0] +; CHECK-ALIGNED-OPTSIZE-NEXT: bx lr +entry: + store i48 %b, i48* %a, align 1 + ret void +} + +define void @loadstore8_align4_minsize(double* %a, double* %b) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: loadstore8_align4_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: mov r4, r1 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread8 +; CHECK-V6M-MINSIZE-NEXT: mov r2, r4 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uwrite8 +; CHECK-V6M-MINSIZE-NEXT: pop {r4, pc} +; +; CHECK-V7M-MINSIZE-LABEL: loadstore8_align4_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: mov r4, r1 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread8 +; CHECK-V7M-MINSIZE-NEXT: mov r2, r4 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uwrite8 +; CHECK-V7M-MINSIZE-NEXT: pop {r4, pc} +; +entry: + %tmp = load double, double* %a, align 1 + store double %tmp, double* %b, align 1 + ret void +} + +define void @loadstore8_align4_optsize(double* %a, double* %b) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: loadstore8_align4_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NEXT: .save {r4, r5, r6, r7, lr} +; CHECK-V6M-OPTSIZE-NEXT: push {r4, r5, r6, r7, lr} +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread8 +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uwrite8 +; CHECK-V6M-OPTSIZE: pop {r4, r5, r6, r7, pc} +; +; CHECK-V7M-OPTSIZE-LABEL: loadstore8_align4_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NEXT: .save {r4, r5, r6, lr} +; CHECK-V7M-OPTSIZE-NEXT: push {r4, r5, r6, lr} +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread8 +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uwrite8 +; CHECK-V7M-OPTSIZE: pop {r4, r5, r6, pc} +entry: + %tmp = load double, double* %a, align 1 + store double %tmp, double* %b, align 1 + ret void +} + +define double @load8_align1_minsize(double* %a) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: load8_align1_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread8 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: load8_align1_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread8 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +; +entry: + %tmp = load double, double* %a, align 1 + ret double %tmp +} + +define double @load8_align1_optsize(double* %a) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: load8_align1_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread8 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: load8_align1_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread8 +; CHECK-V7M-OPTSIZE: bx lr +; +entry: + %tmp = load double, double* %a, align 1 + ret double %tmp +} + +define void @store8_align1_minsize(double* %a, double %b) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: store8_align1_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: mov r1, r3 +; CHECK-V6M-MINSIZE-NEXT: mov r3, r0 +; CHECK-V6M-MINSIZE-NEXT: mov r0, r2 +; CHECK-V6M-MINSIZE-NEXT: mov r2, r3 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uwrite8 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: store8_align1_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: mov r1, r3 +; CHECK-V7M-MINSIZE-NEXT: mov r3, r0 +; CHECK-V7M-MINSIZE-NEXT: mov r0, r2 +; CHECK-V7M-MINSIZE-NEXT: mov r2, r3 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uwrite8 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +entry: + store double %b, double* %a, align 1 + ret void +} + +define void @store8_align1_optsize(double* %a, double %b) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: store8_align1_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uwrite8 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: store8_align1_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uwrite8 +; CHECK-V7M-OPTSIZE: bx lr +entry: + store double %b, double* %a, align 1 + ret void +} + +define double @load8_align2_minsize(double* %a) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: load8_align2_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread8 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: load8_align2_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread8 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +entry: + %tmp = load double, double* %a, align 2 + ret double %tmp +} + +define double @load8_align2_optsize(double* %a) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: load8_align2_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread8 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: load8_align2_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uread8 +; CHECK-V7M-OPTSIZE: bx lr +entry: + %tmp = load double, double* %a, align 2 + ret double %tmp +} + +define i64 @load12_align1_trunc_minsize(i96* %a) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: load12_align1_trunc_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uread8 +; CHECK-V6M-MINSIZE-NEXT: pop {r7, pc} +; +; CHECK-V7M-MINSIZE-LABEL: load12_align1_trunc_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r7, lr} +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uread8 +; CHECK-V7M-MINSIZE-NEXT: pop {r7, pc} +entry: + %tmp = load i96, i96* %a, align 1 + %ext = trunc i96 %tmp to i64 + ret i64 %ext +} + +define i64 @load12_align1_trunc_optsize(i96* %a) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: load12_align1_trunc_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uread8 +; CHECK-V6M-OPTSIZE: bx lr +; +; CHECK-V7M-OPTSIZE-LABEL: load12_align1_trunc_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bx __aeabi_uread8 +; CHECK-V7M-OPTSIZE: bx lr +entry: + %tmp = load i96, i96* %a, align 1 + %ext = trunc i96 %tmp to i64 + ret i64 %ext +} + +define void @store12_align4_trunc_minsize(i96* %a, i96 %b) nounwind minsize { +; CHECK-V6M-MINSIZE-LABEL: store12_align4_trunc_minsize: +; CHECK-V6M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V6M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V6M-MINSIZE-NEXT: mov r1, r3 +; CHECK-V6M-MINSIZE-NEXT: mov r4, r0 +; CHECK-V6M-MINSIZE-NEXT: mov r0, r2 +; CHECK-V6M-MINSIZE-NEXT: mov r2, r4 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uwrite8 +; CHECK-V6M-MINSIZE-NEXT: adds r4, #8 +; CHECK-V6M-MINSIZE-NEXT: ldr r0, [sp, #8] +; CHECK-V6M-MINSIZE-NEXT: mov r1, r4 +; CHECK-V6M-MINSIZE-NEXT: bl __aeabi_uwrite4 +; CHECK-V6M-MINSIZE-NEXT: pop {r4, pc} +; +; CHECK-V7M-MINSIZE-LABEL: store12_align4_trunc_minsize: +; CHECK-V7M-MINSIZE: @ %bb.0: @ %entry +; CHECK-V7M-MINSIZE-NEXT: .save {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: push {r4, lr} +; CHECK-V7M-MINSIZE-NEXT: mov r4, r0 +; CHECK-V7M-MINSIZE-NEXT: mov r0, r2 +; CHECK-V7M-MINSIZE-NEXT: mov r1, r3 +; CHECK-V7M-MINSIZE-NEXT: mov r2, r4 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uwrite8 +; CHECK-V7M-MINSIZE-NEXT: ldr r0, [sp, #8] +; CHECK-V7M-MINSIZE-NEXT: add.w r1, r4, #8 +; CHECK-V7M-MINSIZE-NEXT: bl __aeabi_uwrite4 +; CHECK-V7M-MINSIZE-NEXT: pop {r4, pc} +entry: + store i96 %b, i96* %a, align 1 + ret void +} + +define void @store12_align4_trunc_optsize(i96* %a, i96 %b) nounwind optsize { +; CHECK-V6M-OPTSIZE-LABEL: store12_align4_trunc_optsize: +; CHECK-V6M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V6M-OPTSIZE-NEXT: .save {r4, lr} +; CHECK-V6M-OPTSIZE-NEXT: push {r4, lr} +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uwrite8 +; CHECK-V6M-OPTSIZE-NOT: bl __aeabi_uwrite4 +; CHECK-V6M-OPTSIZE: pop {r4, pc} +; +; CHECK-V7M-OPTSIZE-LABEL: store12_align4_trunc_optsize: +; CHECK-V7M-OPTSIZE: @ %bb.0: @ %entry +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uwrite8 +; CHECK-V7M-OPTSIZE-NOT: bl __aeabi_uwrite4 +; CHECK-V7M-OPTSIZE: bx lr +entry: + store i96 %b, i96* %a, align 1 + ret void +}