Index: llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.h =================================================================== --- llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.h +++ llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.h @@ -101,7 +101,6 @@ bool CanReturnSmallStruct(const Function* CalleeFn, unsigned& RetSize) const; - void promoteLdStType(MVT VT, MVT PromotedLdStVT); public: explicit HexagonTargetLowering(const TargetMachine &TM, @@ -146,6 +145,8 @@ const override; SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; + void LowerOperationWrapper(SDNode *N, SmallVectorImpl &Results, + SelectionDAG &DAG) const override; void ReplaceNodeResults(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const override; @@ -164,6 +165,8 @@ SDValue LowerANY_EXTEND(SDValue Op, SelectionDAG &DAG) const; SDValue LowerSIGN_EXTEND(SDValue Op, SelectionDAG &DAG) const; SDValue LowerZERO_EXTEND(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerLoad(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerStore(SDValue Op, SelectionDAG &DAG) const; SDValue LowerUnalignedLoad(SDValue Op, SelectionDAG &DAG) const; SDValue LowerAddSubCarry(SDValue Op, SelectionDAG &DAG) const; @@ -314,6 +317,9 @@ private: void initializeHVXLowering(); + void validateConstPtrAlignment(SDValue Ptr, const SDLoc &dl, + unsigned NeedAlign) const; + std::pair getBaseAndOffset(SDValue Addr) const; bool getBuildVectorConstInts(ArrayRef Values, MVT VecTy, Index: llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.cpp +++ llvm/trunk/lib/Target/Hexagon/HexagonISelLowering.cpp @@ -151,16 +151,6 @@ #include "HexagonGenCallingConv.inc" -void HexagonTargetLowering::promoteLdStType(MVT VT, MVT PromotedLdStVT) { - if (VT != PromotedLdStVT) { - setOperationAction(ISD::LOAD, VT, Promote); - AddPromotedToType(ISD::LOAD, VT, PromotedLdStVT); - - setOperationAction(ISD::STORE, VT, Promote); - AddPromotedToType(ISD::STORE, VT, PromotedLdStVT); - } -} - SDValue HexagonTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const { @@ -1403,12 +1393,6 @@ // Handling of vector operations. // - promoteLdStType(MVT::v4i8, MVT::i32); - promoteLdStType(MVT::v2i16, MVT::i32); - promoteLdStType(MVT::v8i8, MVT::i64); - promoteLdStType(MVT::v4i16, MVT::i64); - promoteLdStType(MVT::v2i32, MVT::i64); - // Set the action for vector operations to "expand", then override it with // either "custom" or "legal" for specific cases. static const unsigned VectExpOps[] = { @@ -1488,9 +1472,13 @@ } // Custom lower unaligned loads. - for (MVT VecVT : {MVT::i32, MVT::v4i8, MVT::i64, MVT::v8i8, - MVT::v2i16, MVT::v4i16, MVT::v2i32}) { - setOperationAction(ISD::LOAD, VecVT, Custom); + // Also, for both loads and stores, verify the alignment of the address + // in case it is a compile-time constant. This is a usability feature to + // provide a meaningful error message to users. + for (MVT VT : {MVT::i16, MVT::i32, MVT::v4i8, MVT::i64, MVT::v8i8, + MVT::v2i16, MVT::v4i16, MVT::v2i32}) { + setOperationAction(ISD::LOAD, VT, Custom); + setOperationAction(ISD::STORE, VT, Custom); } for (MVT VT : {MVT::v2i16, MVT::v4i8, MVT::v2i32, MVT::v4i16, MVT::v2i32}) { @@ -1738,6 +1726,26 @@ return nullptr; } +void +HexagonTargetLowering::validateConstPtrAlignment(SDValue Ptr, const SDLoc &dl, + unsigned NeedAlign) const { + auto *CA = dyn_cast(Ptr); + if (!CA) + return; + unsigned Addr = CA->getZExtValue(); + unsigned HaveAlign = Addr != 0 ? 1u << countTrailingZeros(Addr) : NeedAlign; + if (HaveAlign < NeedAlign) { + std::string ErrMsg; + raw_string_ostream O(ErrMsg); + O << "Misaligned constant address: " << format_hex(Addr, 10) + << " has alignment " << HaveAlign + << ", but the memory access requires " << NeedAlign; + if (DebugLoc DL = dl.getDebugLoc()) + DL.print(O << ", at "); + report_fatal_error(O.str()); + } +} + // Bit-reverse Load Intrinsic: Check if the instruction is a bit reverse load // intrinsic. static bool isBrevLdIntrinsic(const Value *Inst) { @@ -2643,12 +2651,37 @@ } SDValue +HexagonTargetLowering::LowerLoad(SDValue Op, SelectionDAG &DAG) const { + LoadSDNode *LN = cast(Op.getNode()); + unsigned ClaimAlign = LN->getAlignment(); + validateConstPtrAlignment(LN->getBasePtr(), SDLoc(Op), ClaimAlign); + // Call LowerUnalignedLoad for all loads, it recognizes loads that + // don't need extra aligning. + return LowerUnalignedLoad(Op, DAG); +} + +SDValue +HexagonTargetLowering::LowerStore(SDValue Op, SelectionDAG &DAG) const { + StoreSDNode *SN = cast(Op.getNode()); + unsigned ClaimAlign = SN->getAlignment(); + SDValue Ptr = SN->getBasePtr(); + const SDLoc &dl(Op); + validateConstPtrAlignment(Ptr, dl, ClaimAlign); + + MVT StoreTy = SN->getMemoryVT().getSimpleVT(); + unsigned NeedAlign = Subtarget.getTypeAlignment(StoreTy); + if (ClaimAlign < NeedAlign) + return expandUnalignedStore(SN, DAG); + return Op; +} + +SDValue HexagonTargetLowering::LowerUnalignedLoad(SDValue Op, SelectionDAG &DAG) const { LoadSDNode *LN = cast(Op.getNode()); - unsigned HaveAlign = LN->getAlignment(); MVT LoadTy = ty(Op); unsigned NeedAlign = Subtarget.getTypeAlignment(LoadTy); + unsigned HaveAlign = LN->getAlignment(); if (HaveAlign >= NeedAlign) return Op; @@ -2802,7 +2835,8 @@ case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG); case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG); case ISD::BITCAST: return LowerBITCAST(Op, DAG); - case ISD::LOAD: return LowerUnalignedLoad(Op, DAG); + case ISD::LOAD: return LowerLoad(Op, DAG); + case ISD::STORE: return LowerStore(Op, DAG); case ISD::ADDCARRY: case ISD::SUBCARRY: return LowerAddSubCarry(Op, DAG); case ISD::SRA: @@ -2834,6 +2868,19 @@ } void +HexagonTargetLowering::LowerOperationWrapper(SDNode *N, + SmallVectorImpl &Results, + SelectionDAG &DAG) const { + // We are only custom-lowering stores to verify the alignment of the + // address if it is a compile-time constant. Since a store can be modified + // during type-legalization (the value being stored may need legalization), + // return empty Results here to indicate that we don't really make any + // changes in the custom lowering. + if (N->getOpcode() != ISD::STORE) + return TargetLowering::LowerOperationWrapper(N, Results, DAG); +} + +void HexagonTargetLowering::ReplaceNodeResults(SDNode *N, SmallVectorImpl &Results, SelectionDAG &DAG) const { Index: llvm/trunk/lib/Target/Hexagon/HexagonPatterns.td =================================================================== --- llvm/trunk/lib/Target/Hexagon/HexagonPatterns.td +++ llvm/trunk/lib/Target/Hexagon/HexagonPatterns.td @@ -2306,16 +2306,26 @@ // GP-relative address let AddedComplexity = 120 in { - def: Storea_pat; - def: Storea_pat; - def: Storea_pat; - def: Storea_pat; - def: Storea_pat; - def: Storea_pat; - def: Storea_pat, I32, addrgp, S2_storerbgp>; - def: Storea_pat, I32, addrgp, S2_storerhgp>; - def: Storea_pat, I32, addrgp, S2_storerigp>; - def: Storea_pat, I64, addrgp, S2_storerdgp>; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat, I32, addrgp, S2_storerbgp>; + def: Storea_pat, I32, addrgp, S2_storerhgp>; + def: Storea_pat, I32, addrgp, S2_storerigp>; + def: Storea_pat, V4I8, addrgp, S2_storerigp>; + def: Storea_pat, V2I16, addrgp, S2_storerigp>; + def: Storea_pat, I64, addrgp, S2_storerdgp>; + def: Storea_pat, V8I8, addrgp, S2_storerdgp>; + def: Storea_pat, V4I16, addrgp, S2_storerdgp>; + def: Storea_pat, V2I32, addrgp, S2_storerdgp>; def: Stoream_pat; def: Stoream_pat; @@ -2325,16 +2335,26 @@ // Absolute address let AddedComplexity = 110 in { - def: Storea_pat; - def: Storea_pat; - def: Storea_pat; - def: Storea_pat; - def: Storea_pat; - def: Storea_pat; - def: Storea_pat, I32, anyimm0, PS_storerbabs>; - def: Storea_pat, I32, anyimm1, PS_storerhabs>; - def: Storea_pat, I32, anyimm2, PS_storeriabs>; - def: Storea_pat, I64, anyimm3, PS_storerdabs>; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat; + def: Storea_pat, I32, anyimm0, PS_storerbabs>; + def: Storea_pat, I32, anyimm1, PS_storerhabs>; + def: Storea_pat, I32, anyimm2, PS_storeriabs>; + def: Storea_pat, V4I8, anyimm2, PS_storeriabs>; + def: Storea_pat, V2I16, anyimm2, PS_storeriabs>; + def: Storea_pat, I64, anyimm3, PS_storerdabs>; + def: Storea_pat, V8I8, anyimm3, PS_storerdabs>; + def: Storea_pat, V4I16, anyimm3, PS_storerdabs>; + def: Storea_pat, V2I32, anyimm3, PS_storerdabs>; def: Stoream_pat; def: Stoream_pat; @@ -2344,12 +2364,17 @@ // Reg<; - def: Storexu_shl_pat; - def: Storexu_shl_pat; - def: Storexu_shl_pat; - def: Storexu_shl_pat; - def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; + def: Storexu_shl_pat; def: Pat<(store I1:$Pu, (add (shl I32:$Rs, u2_0ImmPred:$u2), anyimm:$A)), (S4_storerb_ur IntRegs:$Rs, imm:$u2, imm:$A, (I1toI32 I1:$Pu))>; @@ -2357,12 +2382,17 @@ // Reg<; - def: Storexr_shl_pat; - def: Storexr_shl_pat; - def: Storexr_shl_pat; - def: Storexr_shl_pat; - def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; + def: Storexr_shl_pat; def: Pat<(store I1:$Pu, (add (shl I32:$Rs, u2_0ImmPred:$u2), I32:$Rt)), (S4_storerb_ur IntRegs:$Rt, IntRegs:$Rs, imm:$u2, (I1toI32 I1:$Pu))>; @@ -2414,20 +2444,30 @@ // Fi+Imm, Fi, store-register let AddedComplexity = 60 in { - defm: Storexi_fi_add_pat; - defm: Storexi_fi_add_pat; - defm: Storexi_fi_add_pat; - defm: Storexi_fi_add_pat; - defm: Storexi_fi_add_pat; - defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; + defm: Storexi_fi_add_pat; defm: Storexim_fi_add_pat; - def: Storexi_fi_pat; - def: Storexi_fi_pat; - def: Storexi_fi_pat; - def: Storexi_fi_pat; - def: Storexi_fi_pat; - def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; + def: Storexi_fi_pat; def: Storexim_fi_pat; } @@ -2452,32 +2492,47 @@ // Reg+Imm, store-register let AddedComplexity = 40 in { - defm: Storexi_pat; - defm: Storexi_pat; - defm: Storexi_pat; - defm: Storexi_pat; - defm: Storexi_pat; - defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; + defm: Storexi_pat; defm: Storexim_pat; defm: Storexim_pat; defm: Storexim_pat; defm: Storexim_pat; - defm: Storexi_pat, I32, anyimm0, S2_storerb_io>; - defm: Storexi_pat, I32, anyimm1, S2_storerh_io>; - defm: Storexi_pat, I32, anyimm2, S2_storeri_io>; - defm: Storexi_pat, I64, anyimm3, S2_storerd_io>; + defm: Storexi_pat, I32, anyimm0, S2_storerb_io>; + defm: Storexi_pat, I32, anyimm1, S2_storerh_io>; + defm: Storexi_pat, I32, anyimm2, S2_storeri_io>; + defm: Storexi_pat, V4I8, anyimm2, S2_storeri_io>; + defm: Storexi_pat, V2I16, anyimm2, S2_storeri_io>; + defm: Storexi_pat, I64, anyimm3, S2_storerd_io>; + defm: Storexi_pat, V8I8, anyimm3, S2_storerd_io>; + defm: Storexi_pat, V4I16, anyimm3, S2_storerd_io>; + defm: Storexi_pat, V2I32, anyimm3, S2_storerd_io>; } // Reg+Reg let AddedComplexity = 30 in { - def: Storexr_add_pat; - def: Storexr_add_pat; - def: Storexr_add_pat; - def: Storexr_add_pat; - def: Storexr_add_pat; - def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; + def: Storexr_add_pat; def: Pat<(store I1:$Pu, (add I32:$Rs, I32:$Rt)), (S4_storerb_rr IntRegs:$Rs, IntRegs:$Rt, 0, (I1toI32 I1:$Pu))>; @@ -2496,22 +2551,32 @@ // Reg, store-register let AddedComplexity = 10 in { - def: Storexi_base_pat; - def: Storexi_base_pat; - def: Storexi_base_pat; - def: Storexi_base_pat; - def: Storexi_base_pat; - def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; + def: Storexi_base_pat; def: Storexim_base_pat; def: Storexim_base_pat; def: Storexim_base_pat; def: Storexim_base_pat; - def: Storexi_base_pat, I32, S2_storerb_io>; - def: Storexi_base_pat, I32, S2_storerh_io>; - def: Storexi_base_pat, I32, S2_storeri_io>; - def: Storexi_base_pat, I64, S2_storerd_io>; + def: Storexi_base_pat, I32, S2_storerb_io>; + def: Storexi_base_pat, I32, S2_storerh_io>; + def: Storexi_base_pat, I32, S2_storeri_io>; + def: Storexi_base_pat, V4I8, S2_storeri_io>; + def: Storexi_base_pat, V2I16, S2_storeri_io>; + def: Storexi_base_pat, I64, S2_storerd_io>; + def: Storexi_base_pat, V8I8, S2_storerd_io>; + def: Storexi_base_pat, V4I16, S2_storerd_io>; + def: Storexi_base_pat, V2I32, S2_storerd_io>; } Index: llvm/trunk/test/CodeGen/Hexagon/misaligned-const-load.ll =================================================================== --- llvm/trunk/test/CodeGen/Hexagon/misaligned-const-load.ll +++ llvm/trunk/test/CodeGen/Hexagon/misaligned-const-load.ll @@ -0,0 +1,38 @@ +; RUN: not llc -march=hexagon < %s 2>&1 | FileCheck %s + +; Check that the misaligned load is diagnosed. +; CHECK: LLVM ERROR: Misaligned constant address: 0x00012345 has alignment 1, but the memory access requires 4, at misaligned-const-load.c:2:10 + +target triple = "hexagon" + +define i32 @bad_load() #0 !dbg !10 { +entry: + %0 = load i32, i32* inttoptr (i32 74565 to i32*), align 4, !dbg !13, !tbaa !14 + ret i32 %0, !dbg !18 +} + +attributes #0 = { norecurse nounwind readonly "target-cpu"="hexagonv60" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 (http://llvm.org/git/clang.git 3fb90d137ea16e5c3a4580b9db5fd18d93df1a90) (http://llvm.org/git/llvm.git daf385e5698c00fdd693fac736acc96b95ccccd3)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3) +!1 = !DIFile(filename: "misaligned-const-load.c", directory: "/test") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 32) +!5 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!6 = !{i32 2, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !{i32 1, !"wchar_size", i32 4} +!9 = !{!"clang version 8.0.0 (http://llvm.org/git/clang.git 3fb90d137ea16e5c3a4580b9db5fd18d93df1a90) (http://llvm.org/git/llvm.git daf385e5698c00fdd693fac736acc96b95ccccd3)"} +!10 = distinct !DISubprogram(name: "bad_load", scope: !1, file: !1, line: 1, type: !11, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2) +!11 = !DISubroutineType(types: !12) +!12 = !{!5} +!13 = !DILocation(line: 2, column: 10, scope: !10) +!14 = !{!15, !15, i64 0} +!15 = !{!"int", !16, i64 0} +!16 = !{!"omnipotent char", !17, i64 0} +!17 = !{!"Simple C/C++ TBAA"} +!18 = !DILocation(line: 2, column: 3, scope: !10) Index: llvm/trunk/test/CodeGen/Hexagon/misaligned-const-store.ll =================================================================== --- llvm/trunk/test/CodeGen/Hexagon/misaligned-const-store.ll +++ llvm/trunk/test/CodeGen/Hexagon/misaligned-const-store.ll @@ -0,0 +1,38 @@ +; RUN: not llc -march=hexagon < %s 2>&1 | FileCheck %s + +; Check that the misaligned store is diagnosed. +; CHECK: LLVM ERROR: Misaligned constant address: 0x00012345 has alignment 1, but the memory access requires 4, at misaligned-const-store.c:2:10 + +target triple = "hexagon" + +define void @bad_store(i32 %a0) #0 !dbg !10 { +entry: + store i32 %a0, i32* inttoptr (i32 74565 to i32*), align 4, !dbg !13, !tbaa !14 + ret void, !dbg !18 +} + +attributes #0 = { norecurse nounwind readonly "target-cpu"="hexagonv60" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!6, !7, !8} +!llvm.ident = !{!9} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 8.0.0 (http://llvm.org/git/clang.git 3fb90d137ea16e5c3a4580b9db5fd18d93df1a90) (http://llvm.org/git/llvm.git daf385e5698c00fdd693fac736acc96b95ccccd3)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3) +!1 = !DIFile(filename: "misaligned-const-store.c", directory: "/test") +!2 = !{} +!3 = !{!4} +!4 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 32) +!5 = !DIBasicType(name: "unsigned int", size: 32, encoding: DW_ATE_unsigned) +!6 = !{i32 2, !"Dwarf Version", i32 4} +!7 = !{i32 2, !"Debug Info Version", i32 3} +!8 = !{i32 1, !"wchar_size", i32 4} +!9 = !{!"clang version 8.0.0 (http://llvm.org/git/clang.git 3fb90d137ea16e5c3a4580b9db5fd18d93df1a90) (http://llvm.org/git/llvm.git daf385e5698c00fdd693fac736acc96b95ccccd3)"} +!10 = distinct !DISubprogram(name: "bad_store", scope: !1, file: !1, line: 1, type: !11, isLocal: false, isDefinition: true, scopeLine: 1, isOptimized: true, unit: !0, retainedNodes: !2) +!11 = !DISubroutineType(types: !12) +!12 = !{!5} +!13 = !DILocation(line: 2, column: 10, scope: !10) +!14 = !{!15, !15, i64 0} +!15 = !{!"int", !16, i64 0} +!16 = !{!"omnipotent char", !17, i64 0} +!17 = !{!"Simple C/C++ TBAA"} +!18 = !DILocation(line: 2, column: 3, scope: !10)