From 2b264247a9dfcad7093b492a8484a9c7244daf18 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Wed, 25 Jul 2018 21:38:30 +0000 Subject: [PATCH] [SelectionDAG] try to convert funnel shift directly to rotate if legal If the DAGCombiner's rotate matching was working as expected, I don't think we'd see any test diffs here. This sidesteps the issue of custom lowering for rotates raised in PR38243: https://bugs.llvm.org/show_bug.cgi?id=38243 ...by only dealing with legal operations. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@337966 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/CodeGen/ISDOpcodes.h | 2 ++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 11 ++++++++++- test/CodeGen/AArch64/funnel-shift-rot.ll | 6 +----- test/CodeGen/PowerPC/funnel-shift-rot.ll | 4 +--- test/CodeGen/X86/funnel-shift-rot.ll | 8 ++++---- 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/include/llvm/CodeGen/ISDOpcodes.h b/include/llvm/CodeGen/ISDOpcodes.h index 14084e6e1bf..80bd796d537 100644 --- a/include/llvm/CodeGen/ISDOpcodes.h +++ b/include/llvm/CodeGen/ISDOpcodes.h @@ -377,6 +377,8 @@ namespace ISD { /// When the 1st operand is a vector, the shift amount must be in the same /// type. (TLI.getShiftAmountTy() will return the same type when the input /// type is a vector.) + /// For rotates, the shift amount is treated as an unsigned amount modulo + /// the element size of the first operand. SHL, SRA, SRL, ROTL, ROTR, /// Byte Swap and Counting operators. diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index b9c7a8f5bc3..12ce222075b 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5672,7 +5672,16 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { SDValue Z = getValue(I.getArgOperand(2)); EVT VT = X.getValueType(); - // TODO: When X == Y, this is rotate. Create the node directly if legal. + // When X == Y, this is rotate. Create the node directly if legal. + // TODO: This should also be done if the operation is custom, but we have + // to make sure targets are handling the modulo shift amount as expected. + // TODO: If the rotate direction (left or right) corresponding to the shift + // is not available, adjust the shift value and invert the direction. + auto RotateOpcode = IsFSHL ? ISD::ROTL : ISD::ROTR; + if (X == Y && TLI.isOperationLegal(RotateOpcode, VT)) { + setValue(&I, DAG.getNode(RotateOpcode, sdl, VT, X, Z)); + return nullptr; + } // Get the shift amount and inverse shift amount, modulo the bit-width. SDValue BitWidthC = DAG.getConstant(VT.getScalarSizeInBits(), sdl, VT); diff --git a/test/CodeGen/AArch64/funnel-shift-rot.ll b/test/CodeGen/AArch64/funnel-shift-rot.ll index 0b3bc665bdf..af612eafd33 100644 --- a/test/CodeGen/AArch64/funnel-shift-rot.ll +++ b/test/CodeGen/AArch64/funnel-shift-rot.ll @@ -163,11 +163,7 @@ define i32 @rotr_i32(i32 %x, i32 %z) { define i64 @rotr_i64(i64 %x, i64 %z) { ; CHECK-LABEL: rotr_i64: ; CHECK: // %bb.0: -; CHECK-NEXT: orr w9, wzr, #0x40 -; CHECK-NEXT: sub w9, w9, w1 -; CHECK-NEXT: lsr x8, x0, x1 -; CHECK-NEXT: lsl x9, x0, x9 -; CHECK-NEXT: orr x0, x9, x8 +; CHECK-NEXT: ror x0, x0, x1 ; CHECK-NEXT: ret %f = call i64 @llvm.fshr.i64(i64 %x, i64 %x, i64 %z) ret i64 %f diff --git a/test/CodeGen/PowerPC/funnel-shift-rot.ll b/test/CodeGen/PowerPC/funnel-shift-rot.ll index b238504edc1..d93c9361b35 100644 --- a/test/CodeGen/PowerPC/funnel-shift-rot.ll +++ b/test/CodeGen/PowerPC/funnel-shift-rot.ll @@ -55,7 +55,6 @@ define i16 @rotl_i16(i16 %x, i16 %z) { define i32 @rotl_i32(i32 %x, i32 %z) { ; CHECK-LABEL: rotl_i32: ; CHECK: # %bb.0: -; CHECK-NEXT: rlwinm 4, 4, 0, 27, 31 ; CHECK-NEXT: rlwnm 3, 3, 4, 0, 31 ; CHECK-NEXT: blr %f = call i32 @llvm.fshl.i32(i32 %x, i32 %x, i32 %z) @@ -65,8 +64,7 @@ define i32 @rotl_i32(i32 %x, i32 %z) { define i64 @rotl_i64(i64 %x, i64 %z) { ; CHECK-LABEL: rotl_i64: ; CHECK: # %bb.0: -; CHECK-NEXT: rlwinm 4, 4, 0, 26, 31 -; CHECK-NEXT: rotld 3, 3, 4 +; CHECK-NEXT: rldcl 3, 3, 4, 0 ; CHECK-NEXT: blr %f = call i64 @llvm.fshl.i64(i64 %x, i64 %x, i64 %z) ret i64 %f diff --git a/test/CodeGen/X86/funnel-shift-rot.ll b/test/CodeGen/X86/funnel-shift-rot.ll index 2cdea080eea..edbdd8d9b92 100644 --- a/test/CodeGen/X86/funnel-shift-rot.ll +++ b/test/CodeGen/X86/funnel-shift-rot.ll @@ -169,12 +169,12 @@ define i8 @rotr_i8_const_shift(i8 %x) nounwind { ; X32-SSE2-LABEL: rotr_i8_const_shift: ; X32-SSE2: # %bb.0: ; X32-SSE2-NEXT: movb {{[0-9]+}}(%esp), %al -; X32-SSE2-NEXT: rolb $5, %al +; X32-SSE2-NEXT: rorb $3, %al ; X32-SSE2-NEXT: retl ; ; X64-AVX2-LABEL: rotr_i8_const_shift: ; X64-AVX2: # %bb.0: -; X64-AVX2-NEXT: rolb $5, %dil +; X64-AVX2-NEXT: rorb $3, %dil ; X64-AVX2-NEXT: movl %edi, %eax ; X64-AVX2-NEXT: retq %f = call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 3) @@ -185,12 +185,12 @@ define i32 @rotr_i32_const_shift(i32 %x) nounwind { ; X32-SSE2-LABEL: rotr_i32_const_shift: ; X32-SSE2: # %bb.0: ; X32-SSE2-NEXT: movl {{[0-9]+}}(%esp), %eax -; X32-SSE2-NEXT: roll $29, %eax +; X32-SSE2-NEXT: rorl $3, %eax ; X32-SSE2-NEXT: retl ; ; X64-AVX2-LABEL: rotr_i32_const_shift: ; X64-AVX2: # %bb.0: -; X64-AVX2-NEXT: roll $29, %edi +; X64-AVX2-NEXT: rorl $3, %edi ; X64-AVX2-NEXT: movl %edi, %eax ; X64-AVX2-NEXT: retq %f = call i32 @llvm.fshr.i32(i32 %x, i32 %x, i32 3) -- 2.50.1