1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 20:51:52 +01:00

SelectionDAG: Cleanup and simplify FoldConstantArithmetic

This cleans up the FoldConstantArithmetic code by factoring out the case
of two ConstantSDNodes into an own function. This avoids unnecessary
complexity for many callers who already have ConstantSDNode arguments.

This also avoids an intermeidate SmallVector datastructure and a loop
over that datastructure.

llvm-svn: 237651
This commit is contained in:
Matthias Braun 2015-05-19 01:40:21 +00:00
parent 0cf74b4130
commit ed527f2f9e
2 changed files with 97 additions and 102 deletions

View File

@ -1128,6 +1128,10 @@ public:
SDValue FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,
SDNode *Cst1, SDNode *Cst2);
SDValue FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,
const ConstantSDNode *Cst1,
const ConstantSDNode *Cst2);
/// Constant fold a setcc to true or false.
SDValue FoldSetCC(EVT VT, SDValue N1,
SDValue N2, ISD::CondCode Cond, SDLoc dl);

View File

@ -49,6 +49,7 @@
#include "llvm/Target/TargetSubtargetInfo.h"
#include <algorithm>
#include <cmath>
#include <utility>
using namespace llvm;
@ -3109,6 +3110,53 @@ SDValue SelectionDAG::getNode(unsigned Opcode, SDLoc DL,
return SDValue(N, 0);
}
static std::pair<APInt, bool> FoldValue(unsigned Opcode, const APInt &C1,
const APInt &C2) {
switch (Opcode) {
case ISD::ADD: return std::make_pair(C1 + C2, true);
case ISD::SUB: return std::make_pair(C1 - C2, true);
case ISD::MUL: return std::make_pair(C1 * C2, true);
case ISD::AND: return std::make_pair(C1 & C2, true);
case ISD::OR: return std::make_pair(C1 | C2, true);
case ISD::XOR: return std::make_pair(C1 ^ C2, true);
case ISD::SHL: return std::make_pair(C1 << C2, true);
case ISD::SRL: return std::make_pair(C1.lshr(C2), true);
case ISD::SRA: return std::make_pair(C1.ashr(C2), true);
case ISD::ROTL: return std::make_pair(C1.rotl(C2), true);
case ISD::ROTR: return std::make_pair(C1.rotr(C2), true);
case ISD::UDIV:
if (!C2.getBoolValue())
break;
return std::make_pair(C1.udiv(C2), true);
case ISD::UREM:
if (!C2.getBoolValue())
break;
return std::make_pair(C1.urem(C2), true);
case ISD::SDIV:
if (!C2.getBoolValue())
break;
return std::make_pair(C1.sdiv(C2), true);
case ISD::SREM:
if (!C2.getBoolValue())
break;
return std::make_pair(C1.srem(C2), true);
}
return std::make_pair(APInt(1, 0), false);
}
SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,
const ConstantSDNode *Cst1,
const ConstantSDNode *Cst2) {
if (Cst1->isOpaque() || Cst2->isOpaque())
return SDValue();
std::pair<APInt, bool> Folded = FoldValue(Opcode, Cst1->getAPIntValue(),
Cst2->getAPIntValue());
if (!Folded.second)
return SDValue();
return getConstant(Folded.first, DL, VT);
}
SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,
SDNode *Cst1, SDNode *Cst2) {
// If the opcode is a target-specific ISD node, there's nothing we can
@ -3117,116 +3165,59 @@ SDValue SelectionDAG::FoldConstantArithmetic(unsigned Opcode, SDLoc DL, EVT VT,
if (Opcode >= ISD::BUILTIN_OP_END)
return SDValue();
SmallVector<std::pair<ConstantSDNode *, ConstantSDNode *>, 4> Inputs;
SmallVector<SDValue, 4> Outputs;
EVT SVT = VT.getScalarType();
// Handle the case of two scalars.
if (const ConstantSDNode *Scalar1 = dyn_cast<ConstantSDNode>(Cst1)) {
if (const ConstantSDNode *Scalar2 = dyn_cast<ConstantSDNode>(Cst2)) {
if (SDValue Folded =
FoldConstantArithmetic(Opcode, DL, VT, Scalar1, Scalar2)) {
if (!VT.isVector())
return Folded;
SmallVector<SDValue, 4> Outputs;
// We may have a vector type but a scalar result. Create a splat.
Outputs.resize(VT.getVectorNumElements(), Outputs.back());
// Build a big vector out of the scalar elements we generated.
return getNode(ISD::BUILD_VECTOR, SDLoc(), VT, Outputs);
} else {
return SDValue();
}
}
}
ConstantSDNode *Scalar1 = dyn_cast<ConstantSDNode>(Cst1);
ConstantSDNode *Scalar2 = dyn_cast<ConstantSDNode>(Cst2);
if (Scalar1 && Scalar2 && (Scalar1->isOpaque() || Scalar2->isOpaque()))
// For vectors extract each constant element into Inputs so we can constant
// fold them individually.
BuildVectorSDNode *BV1 = dyn_cast<BuildVectorSDNode>(Cst1);
BuildVectorSDNode *BV2 = dyn_cast<BuildVectorSDNode>(Cst2);
if (!BV1 || !BV2)
return SDValue();
if (Scalar1 && Scalar2)
// Scalar instruction.
Inputs.push_back(std::make_pair(Scalar1, Scalar2));
else {
// For vectors extract each constant element into Inputs so we can constant
// fold them individually.
BuildVectorSDNode *BV1 = dyn_cast<BuildVectorSDNode>(Cst1);
BuildVectorSDNode *BV2 = dyn_cast<BuildVectorSDNode>(Cst2);
if (!BV1 || !BV2)
assert(BV1->getNumOperands() == BV2->getNumOperands() && "Out of sync!");
EVT SVT = VT.getScalarType();
SmallVector<SDValue, 4> Outputs;
for (unsigned I = 0, E = BV1->getNumOperands(); I != E; ++I) {
ConstantSDNode *V1 = dyn_cast<ConstantSDNode>(BV1->getOperand(I));
ConstantSDNode *V2 = dyn_cast<ConstantSDNode>(BV2->getOperand(I));
if (!V1 || !V2) // Not a constant, bail.
return SDValue();
assert(BV1->getNumOperands() == BV2->getNumOperands() && "Out of sync!");
for (unsigned I = 0, E = BV1->getNumOperands(); I != E; ++I) {
ConstantSDNode *V1 = dyn_cast<ConstantSDNode>(BV1->getOperand(I));
ConstantSDNode *V2 = dyn_cast<ConstantSDNode>(BV2->getOperand(I));
if (!V1 || !V2) // Not a constant, bail.
return SDValue();
if (V1->isOpaque() || V2->isOpaque())
return SDValue();
// Avoid BUILD_VECTOR nodes that perform implicit truncation.
// FIXME: This is valid and could be handled by truncating the APInts.
if (V1->getValueType(0) != SVT || V2->getValueType(0) != SVT)
return SDValue();
Inputs.push_back(std::make_pair(V1, V2));
}
}
// We have a number of constant values, constant fold them element by element.
for (unsigned I = 0, E = Inputs.size(); I != E; ++I) {
const APInt &C1 = Inputs[I].first->getAPIntValue();
const APInt &C2 = Inputs[I].second->getAPIntValue();
switch (Opcode) {
case ISD::ADD:
Outputs.push_back(getConstant(C1 + C2, DL, SVT));
break;
case ISD::SUB:
Outputs.push_back(getConstant(C1 - C2, DL, SVT));
break;
case ISD::MUL:
Outputs.push_back(getConstant(C1 * C2, DL, SVT));
break;
case ISD::UDIV:
if (!C2.getBoolValue())
return SDValue();
Outputs.push_back(getConstant(C1.udiv(C2), DL, SVT));
break;
case ISD::UREM:
if (!C2.getBoolValue())
return SDValue();
Outputs.push_back(getConstant(C1.urem(C2), DL, SVT));
break;
case ISD::SDIV:
if (!C2.getBoolValue())
return SDValue();
Outputs.push_back(getConstant(C1.sdiv(C2), DL, SVT));
break;
case ISD::SREM:
if (!C2.getBoolValue())
return SDValue();
Outputs.push_back(getConstant(C1.srem(C2), DL, SVT));
break;
case ISD::AND:
Outputs.push_back(getConstant(C1 & C2, DL, SVT));
break;
case ISD::OR:
Outputs.push_back(getConstant(C1 | C2, DL, SVT));
break;
case ISD::XOR:
Outputs.push_back(getConstant(C1 ^ C2, DL, SVT));
break;
case ISD::SHL:
Outputs.push_back(getConstant(C1 << C2, DL, SVT));
break;
case ISD::SRL:
Outputs.push_back(getConstant(C1.lshr(C2), DL, SVT));
break;
case ISD::SRA:
Outputs.push_back(getConstant(C1.ashr(C2), DL, SVT));
break;
case ISD::ROTL:
Outputs.push_back(getConstant(C1.rotl(C2), DL, SVT));
break;
case ISD::ROTR:
Outputs.push_back(getConstant(C1.rotr(C2), DL, SVT));
break;
default:
if (V1->isOpaque() || V2->isOpaque())
return SDValue();
}
// Avoid BUILD_VECTOR nodes that perform implicit truncation.
// FIXME: This is valid and could be handled by truncating the APInts.
if (V1->getValueType(0) != SVT || V2->getValueType(0) != SVT)
return SDValue();
// Fold one vector element.
std::pair<APInt, bool> Folded = FoldValue(Opcode, V1->getAPIntValue(),
V2->getAPIntValue());
if (!Folded.second)
return SDValue();
Outputs.push_back(getConstant(Folded.first, DL, SVT));
}
assert((Scalar1 && Scalar2) || (VT.getVectorNumElements() == Outputs.size() &&
"Expected a scalar or vector!"));
// Handle the scalar case first.
if (!VT.isVector())
return Outputs.back();
assert(VT.getVectorNumElements() == Outputs.size() &&
"Vector size mismatch!");
// We may have a vector type but a scalar result. Create a splat.
Outputs.resize(VT.getVectorNumElements(), Outputs.back());