From 316d3e308530cfa1abdf3e75bbf24640b1beb3c3 Mon Sep 17 00:00:00 2001 From: Adam Nemet Date: Fri, 7 Mar 2014 23:56:28 +0000 Subject: [PATCH] [DAGCombiner] Recognize another rotation idiom This is the new idiom: x<<(y&31) | x>>((0-y)&31) which is recognized as: x ROTL (y&31) The change refines matchRotateSub. In Neg & (OpSize - 1) == (OpSize - Pos) & (OpSize - 1), if Pos is Pos' & (OpSize - 1) we can just use Pos' instead of Pos. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@203315 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 8 ++ test/CodeGen/X86/rotate4.ll | 126 +++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 test/CodeGen/X86/rotate4.ll diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 97885d4f3f8..f9388185b43 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -3466,6 +3466,14 @@ static bool matchRotateSub(SDValue Pos, SDValue Neg, unsigned OpSize) { return 0; SDValue NegOp1 = Neg.getOperand(1); + // On the RHS of [A], if Pos is Pos' & (OpSize - 1), just replace Pos with + // Pos'. The truncation is redundant for the purpose of the equality. + if (MaskLoBits && + Pos.getOpcode() == ISD::AND && + Pos.getOperand(1).getOpcode() == ISD::Constant && + cast(Pos.getOperand(1))->getAPIntValue() == OpSize - 1) + Pos = Pos.getOperand(0); + // The condition we need is now: // // (NegC - NegOp1) & Mask == (OpSize - Pos) & Mask diff --git a/test/CodeGen/X86/rotate4.ll b/test/CodeGen/X86/rotate4.ll new file mode 100644 index 00000000000..31069899195 --- /dev/null +++ b/test/CodeGen/X86/rotate4.ll @@ -0,0 +1,126 @@ +; RUN: llc < %s -mtriple=x86_64-apple-darwin -mcpu=generic | FileCheck %s + +; Check that we recognize this idiom for rotation too: +; a << (b & 31) | a >> ((0 - b) & 31) + +define i32 @rotate_left_32(i32 %a, i32 %b) { +; CHECK-LABEL: rotate_left_32: +; CHECK: roll +entry: + %and = and i32 %b, 31 + %shl = shl i32 %a, %and + %0 = sub i32 0, %b + %and3 = and i32 %0, 31 + %shr = lshr i32 %a, %and3 + %or = or i32 %shl, %shr + ret i32 %or +} + +define i32 @rotate_right_32(i32 %a, i32 %b) { +; CHECK-LABEL: rotate_right_32: +; CHECK: rorl +entry: + %and = and i32 %b, 31 + %shl = lshr i32 %a, %and + %0 = sub i32 0, %b + %and3 = and i32 %0, 31 + %shr = shl i32 %a, %and3 + %or = or i32 %shl, %shr + ret i32 %or +} + +define i64 @rotate_left_64(i64 %a, i64 %b) { +; CHECK-LABEL: rotate_left_64: +; CHECK: rolq +entry: + %and = and i64 %b, 63 + %shl = shl i64 %a, %and + %0 = sub i64 0, %b + %and3 = and i64 %0, 63 + %shr = lshr i64 %a, %and3 + %or = or i64 %shl, %shr + ret i64 %or +} + +define i64 @rotate_right_64(i64 %a, i64 %b) { +; CHECK-LABEL: rotate_right_64: +; CHECK: rorq +entry: + %and = and i64 %b, 63 + %shl = lshr i64 %a, %and + %0 = sub i64 0, %b + %and3 = and i64 %0, 63 + %shr = shl i64 %a, %and3 + %or = or i64 %shl, %shr + ret i64 %or +} + +; Also check mem operand. + +define void @rotate_left_m32(i32 *%pa, i32 %b) { +; CHECK-LABEL: rotate_left_m32: +; CHECK: roll +; no store: +; CHECK-NOT: mov +entry: + %a = load i32* %pa, align 16 + %and = and i32 %b, 31 + %shl = shl i32 %a, %and + %0 = sub i32 0, %b + %and3 = and i32 %0, 31 + %shr = lshr i32 %a, %and3 + %or = or i32 %shl, %shr + store i32 %or, i32* %pa, align 32 + ret void +} + +define void @rotate_right_m32(i32 *%pa, i32 %b) { +; CHECK-LABEL: rotate_right_m32: +; CHECK: rorl +; no store: +; CHECK-NOT: mov +entry: + %a = load i32* %pa, align 16 + %and = and i32 %b, 31 + %shl = lshr i32 %a, %and + %0 = sub i32 0, %b + %and3 = and i32 %0, 31 + %shr = shl i32 %a, %and3 + %or = or i32 %shl, %shr + store i32 %or, i32* %pa, align 32 + ret void +} + +define void @rotate_left_m64(i64 *%pa, i64 %b) { +; CHECK-LABEL: rotate_left_m64: +; CHECK: rolq +; no store: +; CHECK-NOT: mov +entry: + %a = load i64* %pa, align 16 + %and = and i64 %b, 63 + %shl = shl i64 %a, %and + %0 = sub i64 0, %b + %and3 = and i64 %0, 63 + %shr = lshr i64 %a, %and3 + %or = or i64 %shl, %shr + store i64 %or, i64* %pa, align 64 + ret void +} + +define void @rotate_right_m64(i64 *%pa, i64 %b) { +; CHECK-LABEL: rotate_right_m64: +; CHECK: rorq +; no store: +; CHECK-NOT: mov +entry: + %a = load i64* %pa, align 16 + %and = and i64 %b, 63 + %shl = lshr i64 %a, %and + %0 = sub i64 0, %b + %and3 = and i64 %0, 63 + %shr = shl i64 %a, %and3 + %or = or i64 %shl, %shr + store i64 %or, i64* %pa, align 64 + ret void +}