summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/SelectionDAG
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp14
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp40
2 files changed, 52 insertions, 2 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 99340ca3388..da46a847490 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -568,6 +568,16 @@ namespace {
/// single-use) and if missed an empty SDValue is returned.
SDValue distributeTruncateThroughAnd(SDNode *N);
+ /// Helper function to determine whether the target supports operation
+ /// given by \p Opcode for type \p VT, that is, whether the operation
+ /// is legal or custom before legalizing operations, and whether is
+ /// legal (but not custom) after legalization.
+ bool hasOperation(unsigned Opcode, EVT VT) {
+ if (LegalOperations)
+ return TLI.isOperationLegal(Opcode, VT);
+ return TLI.isOperationLegalOrCustom(Opcode, VT);
+ }
+
public:
/// Runs the dag combiner on all nodes in the work list
void Run(CombineLevel AtLevel);
@@ -5050,8 +5060,8 @@ SDNode *DAGCombiner::MatchRotate(SDValue LHS, SDValue RHS, const SDLoc &DL) {
if (!TLI.isTypeLegal(VT)) return nullptr;
// The target must have at least one rotate flavor.
- bool HasROTL = TLI.isOperationLegalOrCustom(ISD::ROTL, VT);
- bool HasROTR = TLI.isOperationLegalOrCustom(ISD::ROTR, VT);
+ bool HasROTL = hasOperation(ISD::ROTL, VT);
+ bool HasROTR = hasOperation(ISD::ROTR, VT);
if (!HasROTL && !HasROTR) return nullptr;
// Check for truncated rotate.
diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
index 4fe55f790d4..c98d03f70a1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
@@ -3899,6 +3899,46 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
ReplaceNode(SDValue(Node, 0), Result);
break;
}
+ case ISD::ROTL:
+ case ISD::ROTR: {
+ bool IsLeft = Node->getOpcode() == ISD::ROTL;
+ SDValue Op0 = Node->getOperand(0), Op1 = Node->getOperand(1);
+ EVT ResVT = Node->getValueType(0);
+ EVT OpVT = Op0.getValueType();
+ assert(OpVT == ResVT &&
+ "The result and the operand types of rotate should match");
+ EVT ShVT = Op1.getValueType();
+ SDValue Width = DAG.getConstant(OpVT.getScalarSizeInBits(), dl, ShVT);
+
+ // If a rotate in the other direction is legal, use it.
+ unsigned RevRot = IsLeft ? ISD::ROTR : ISD::ROTL;
+ if (TLI.isOperationLegal(RevRot, ResVT)) {
+ SDValue Sub = DAG.getNode(ISD::SUB, dl, ShVT, Width, Op1);
+ Results.push_back(DAG.getNode(RevRot, dl, ResVT, Op0, Sub));
+ break;
+ }
+
+ // Otherwise,
+ // (rotl x, c) -> (or (shl x, (and c, w-1)), (srl x, (and w-c, w-1)))
+ // (rotr x, c) -> (or (srl x, (and c, w-1)), (shl x, (and w-c, w-1)))
+ //
+ assert(isPowerOf2_32(OpVT.getScalarSizeInBits()) &&
+ "Expecting the type bitwidth to be a power of 2");
+ unsigned ShOpc = IsLeft ? ISD::SHL : ISD::SRL;
+ unsigned HsOpc = IsLeft ? ISD::SRL : ISD::SHL;
+ SDValue Width1 = DAG.getNode(ISD::SUB, dl, ShVT,
+ Width, DAG.getConstant(1, dl, ShVT));
+ SDValue NegOp1 = DAG.getNode(ISD::SUB, dl, ShVT, Width, Op1);
+ SDValue And0 = DAG.getNode(ISD::AND, dl, ShVT, Op1, Width1);
+ SDValue And1 = DAG.getNode(ISD::AND, dl, ShVT, NegOp1, Width1);
+
+ SDValue Or = DAG.getNode(ISD::OR, dl, ResVT,
+ DAG.getNode(ShOpc, dl, ResVT, Op0, And0),
+ DAG.getNode(HsOpc, dl, ResVT, Op0, And1));
+ Results.push_back(Or);
+ break;
+ }
+
case ISD::GLOBAL_OFFSET_TABLE:
case ISD::GlobalAddress:
case ISD::GlobalTLSAddress:
OpenPOWER on IntegriCloud