From c7a10fc5eda26dc92f13a86a5a28fed522c56065 Mon Sep 17 00:00:00 2001 From: Krzysztof Parzyszek Date: Wed, 22 Jun 2016 20:08:27 +0000 Subject: [PATCH] [Hexagon] Add SDAG preprocessing step to expose shifted addressing modes Transform: (store ch addr (add x (add (shl y c) e))) to: (store ch addr (add x (shl (add y d) c))), where e = (shl d c) for some integer d. The purpose of this is to enable generation of loads/stores with shifted addressing mode, i.e. mem(x+y<<#c). For that, the shift value c must be 0, 1 or 2. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@273466 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Hexagon/HexagonISelDAGToDAG.cpp | 55 +++++++++++++++++++++- test/CodeGen/Hexagon/store-shift.ll | 50 ++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 test/CodeGen/Hexagon/store-shift.ll diff --git a/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp b/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp index 277d9b1f7d2..1ddb9327776 100644 --- a/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp +++ b/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp @@ -1408,7 +1408,7 @@ void HexagonDAGToDAGISel::PreprocessISelDAG() { // Simplify: (or (select c x 0) z) -> (select c (or x z) z) // (or (select c 0 y) z) -> (select c z (or y z)) // This may not be the right thing for all targets, so do it here. - for (auto I: Nodes) { + for (auto I : Nodes) { if (I->getOpcode() != ISD::OR) continue; @@ -1445,6 +1445,59 @@ void HexagonDAGToDAGISel::PreprocessISelDAG() { } } } + + // Transform: (store ch addr (add x (add (shl y c) e))) + // to: (store ch addr (add x (shl (add y d) c))), + // where e = (shl d c) for some integer d. + // The purpose of this is to enable generation of loads/stores with + // shifted addressing mode, i.e. mem(x+y<<#c). For that, the shift + // value c must be 0, 1 or 2. + for (auto I : Nodes) { + if (I->getOpcode() != ISD::STORE) + continue; + + // I matched: (store ch addr Off) + SDValue Off = I->getOperand(2); + // Off needs to match: (add x (add (shl y c) (shl d c)))) + if (Off.getOpcode() != ISD::ADD) + continue; + // Off matched: (add x T0) + SDValue T0 = Off.getOperand(1); + // T0 needs to match: (add T1 T2): + if (T0.getOpcode() != ISD::ADD) + continue; + // T0 matched: (add T1 T2) + SDValue T1 = T0.getOperand(0); + SDValue T2 = T0.getOperand(1); + // T1 needs to match: (shl y c) + if (T1.getOpcode() != ISD::SHL) + continue; + SDValue C = T1.getOperand(1); + ConstantSDNode *CN = dyn_cast(C.getNode()); + if (CN == nullptr) + continue; + unsigned CV = CN->getZExtValue(); + if (CV > 2) + continue; + // T2 needs to match e, where e = (shl d c) for some d. + ConstantSDNode *EN = dyn_cast(T2.getNode()); + if (EN == nullptr) + continue; + unsigned EV = EN->getZExtValue(); + if (EV % (1 << CV) != 0) + continue; + unsigned DV = EV / (1 << CV); + + // Replace T0 with: (shl (add y d) c) + SDLoc DL = SDLoc(I); + EVT VT = T0.getValueType(); + SDValue D = DAG.getConstant(DV, DL, VT); + // NewAdd = (add y d) + SDValue NewAdd = DAG.getNode(ISD::ADD, DL, VT, T1.getOperand(0), D); + // NewShl = (shl NewAdd c) + SDValue NewShl = DAG.getNode(ISD::SHL, DL, VT, NewAdd, C); + ReplaceNode(T0.getNode(), NewShl.getNode()); + } } void HexagonDAGToDAGISel::EmitFunctionEntryCode() { diff --git a/test/CodeGen/Hexagon/store-shift.ll b/test/CodeGen/Hexagon/store-shift.ll new file mode 100644 index 00000000000..866930990ba --- /dev/null +++ b/test/CodeGen/Hexagon/store-shift.ll @@ -0,0 +1,50 @@ +; RUN: llc -march=hexagon < %s | FileCheck %s + +; CHECK-DAG: r[[BASE:[0-9]+]] += add +; CHECK-DAG: r[[IDX0:[0-9]+]] = add(r2, #5) +; CHECK-DAG: r[[IDX1:[0-9]+]] = add(r2, #6) +; CHECK-DAG: memw(r0 + r[[IDX0]]<<#2) = r3 +; CHECK-DAG: memw(r0 + r[[IDX1]]<<#2) = r3 +; CHECK-DAG: memw(r[[BASE]] + r[[IDX0]]<<#2) = r[[IDX0]] +; CHECK-DAG: memw(r[[BASE]] + r[[IDX1]]<<#2) = r[[IDX0]] + +target triple = "hexagon" + +@G = external global i32, align 4 + +; Function Attrs: norecurse nounwind +define void @fred(i32* nocapture %A, [50 x i32]* nocapture %B, i32 %N, i32 %M) #0 { +entry: + %add = add nsw i32 %N, 5 + %arrayidx = getelementptr inbounds i32, i32* %A, i32 %add + store i32 %M, i32* %arrayidx, align 4, !tbaa !1 + %add2 = add nsw i32 %N, 6 + %arrayidx3 = getelementptr inbounds i32, i32* %A, i32 %add2 + store i32 %M, i32* %arrayidx3, align 4, !tbaa !1 + %add4 = add nsw i32 %N, 35 + %arrayidx5 = getelementptr inbounds i32, i32* %A, i32 %add4 + store i32 %add, i32* %arrayidx5, align 4, !tbaa !1 + %arrayidx8 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 %add, i32 %add + store i32 %add, i32* %arrayidx8, align 4, !tbaa !1 + %inc = add nsw i32 %N, 6 + %arrayidx8.1 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 %add, i32 %inc + store i32 %add, i32* %arrayidx8.1, align 4, !tbaa !1 + %sub = add nsw i32 %N, 4 + %arrayidx10 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 %add, i32 %sub + %0 = load i32, i32* %arrayidx10, align 4, !tbaa !1 + %add11 = add nsw i32 %0, 1 + store i32 %add11, i32* %arrayidx10, align 4, !tbaa !1 + %1 = load i32, i32* %arrayidx, align 4, !tbaa !1 + %add13 = add nsw i32 %N, 25 + %arrayidx15 = getelementptr inbounds [50 x i32], [50 x i32]* %B, i32 %add13, i32 %add + store i32 %1, i32* %arrayidx15, align 4, !tbaa !1 + store i32 5, i32* @G, align 4, !tbaa !1 + ret void +} + +attributes #0 = { norecurse nounwind "target-cpu"="hexagonv60" "target-features"="+hvx,-hvx-double" } + +!1 = !{!2, !2, i64 0} +!2 = !{!"int", !3, i64 0} +!3 = !{!"omnipotent char", !4, i64 0} +!4 = !{!"Simple C/C++ TBAA"} -- 2.50.1