#include "LegalizeTypes.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
#define DEBUG_TYPE "legalize-types"
static cl::opt<bool>
EnableExpensiveChecks("enable-legalize-types-checking", cl::Hidden);
void DAGTypeLegalizer::PerformExpensiveChecks() {
SmallVector<SDNode*, 16> NewNodes;
for (SDNode &Node : DAG.allnodes()) {
if (Node.getNodeId() == NewNode)
NewNodes.push_back(&Node);
for (unsigned i = 0, e = Node.getNumValues(); i != e; ++i) {
SDValue Res(&Node, i);
bool Failed = false;
auto ResId = ValueToIdMap.lookup(Res);
unsigned Mapped = 0;
if (ResId) {
auto I = ReplacedValues.find(ResId);
if (I != ReplacedValues.end()) {
Mapped |= 1;
for (SDNode::use_iterator UI = Node.use_begin(), UE = Node.use_end();
UI != UE; ++UI)
if (UI.getUse().getResNo() == i)
assert(UI->getNodeId() == NewNode &&
"Remapped value has non-trivial use!");
auto NewValId = I->second;
I = ReplacedValues.find(NewValId);
while (I != ReplacedValues.end()) {
NewValId = I->second;
I = ReplacedValues.find(NewValId);
}
SDValue NewVal = getSDValue(NewValId);
(void)NewVal;
assert(NewVal.getNode()->getNodeId() != NewNode &&
"ReplacedValues maps to a new node!");
}
if (PromotedIntegers.count(ResId))
Mapped |= 2;
if (SoftenedFloats.count(ResId))
Mapped |= 4;
if (ScalarizedVectors.count(ResId))
Mapped |= 8;
if (ExpandedIntegers.count(ResId))
Mapped |= 16;
if (ExpandedFloats.count(ResId))
Mapped |= 32;
if (SplitVectors.count(ResId))
Mapped |= 64;
if (WidenedVectors.count(ResId))
Mapped |= 128;
if (PromotedFloats.count(ResId))
Mapped |= 256;
if (SoftPromotedHalfs.count(ResId))
Mapped |= 512;
}
if (Node.getNodeId() != Processed) {
if ((Node.getNodeId() == NewNode && Mapped > 1) ||
(Node.getNodeId() != NewNode && Mapped != 0)) {
dbgs() << "Unprocessed value in a map!";
Failed = true;
}
} else if (isTypeLegal(Res.getValueType()) || IgnoreNodeResults(&Node)) {
if (Mapped > 1) {
dbgs() << "Value with legal type was transformed!";
Failed = true;
}
} else {
if (Mapped == 0) {
SDValue NodeById = IdToValueMap.lookup(ResId);
if (NodeById->getNodeId() == Processed) {
dbgs() << "Processed value not in any map!";
Failed = true;
}
} else if (Mapped & (Mapped - 1)) {
dbgs() << "Value in multiple maps!";
Failed = true;
}
}
if (Failed) {
if (Mapped & 1)
dbgs() << " ReplacedValues";
if (Mapped & 2)
dbgs() << " PromotedIntegers";
if (Mapped & 4)
dbgs() << " SoftenedFloats";
if (Mapped & 8)
dbgs() << " ScalarizedVectors";
if (Mapped & 16)
dbgs() << " ExpandedIntegers";
if (Mapped & 32)
dbgs() << " ExpandedFloats";
if (Mapped & 64)
dbgs() << " SplitVectors";
if (Mapped & 128)
dbgs() << " WidenedVectors";
if (Mapped & 256)
dbgs() << " PromotedFloats";
if (Mapped & 512)
dbgs() << " SoftPromoteHalfs";
dbgs() << "\n";
llvm_unreachable(nullptr);
}
}
}
#ifndef NDEBUG
for (unsigned i = 0, e = NewNodes.size(); i != e; ++i) {
SDNode *N = NewNodes[i];
for (SDNode *U : N->uses())
assert(U->getNodeId() == NewNode && "NewNode used by non-NewNode!");
}
#endif
}
bool DAGTypeLegalizer::run() {
bool Changed = false;
HandleSDNode Dummy(DAG.getRoot());
Dummy.setNodeId(Unanalyzed);
DAG.setRoot(SDValue());
for (SDNode &Node : DAG.allnodes()) {
if (Node.getNumOperands() == 0) {
Node.setNodeId(ReadyToProcess);
Worklist.push_back(&Node);
} else {
Node.setNodeId(Unanalyzed);
}
}
while (!Worklist.empty()) {
#ifndef EXPENSIVE_CHECKS
if (EnableExpensiveChecks)
#endif
PerformExpensiveChecks();
SDNode *N = Worklist.pop_back_val();
assert(N->getNodeId() == ReadyToProcess &&
"Node should be ready if on worklist!");
LLVM_DEBUG(dbgs() << "Legalizing node: "; N->dump(&DAG));
if (IgnoreNodeResults(N)) {
LLVM_DEBUG(dbgs() << "Ignoring node results\n");
goto ScanOperands;
}
for (unsigned i = 0, NumResults = N->getNumValues(); i < NumResults; ++i) {
EVT ResultVT = N->getValueType(i);
LLVM_DEBUG(dbgs() << "Analyzing result type: " << ResultVT.getEVTString()
<< "\n");
switch (getTypeAction(ResultVT)) {
case TargetLowering::TypeLegal:
LLVM_DEBUG(dbgs() << "Legal result type\n");
break;
case TargetLowering::TypeScalarizeScalableVector:
report_fatal_error(
"Scalarization of scalable vectors is not supported.");
case TargetLowering::TypePromoteInteger:
PromoteIntegerResult(N, i);
Changed = true;
goto NodeDone;
case TargetLowering::TypeExpandInteger:
ExpandIntegerResult(N, i);
Changed = true;
goto NodeDone;
case TargetLowering::TypeSoftenFloat:
SoftenFloatResult(N, i);
Changed = true;
goto NodeDone;
case TargetLowering::TypeExpandFloat:
ExpandFloatResult(N, i);
Changed = true;
goto NodeDone;
case TargetLowering::TypeScalarizeVector:
ScalarizeVectorResult(N, i);
Changed = true;
goto NodeDone;
case TargetLowering::TypeSplitVector:
SplitVectorResult(N, i);
Changed = true;
goto NodeDone;
case TargetLowering::TypeWidenVector:
WidenVectorResult(N, i);
Changed = true;
goto NodeDone;
case TargetLowering::TypePromoteFloat:
PromoteFloatResult(N, i);
Changed = true;
goto NodeDone;
case TargetLowering::TypeSoftPromoteHalf:
SoftPromoteHalfResult(N, i);
Changed = true;
goto NodeDone;
}
}
ScanOperands:
{
unsigned NumOperands = N->getNumOperands();
bool NeedsReanalyzing = false;
unsigned i;
for (i = 0; i != NumOperands; ++i) {
if (IgnoreNodeResults(N->getOperand(i).getNode()))
continue;
const auto &Op = N->getOperand(i);
LLVM_DEBUG(dbgs() << "Analyzing operand: "; Op.dump(&DAG));
EVT OpVT = Op.getValueType();
switch (getTypeAction(OpVT)) {
case TargetLowering::TypeLegal:
LLVM_DEBUG(dbgs() << "Legal operand\n");
continue;
case TargetLowering::TypeScalarizeScalableVector:
report_fatal_error(
"Scalarization of scalable vectors is not supported.");
case TargetLowering::TypePromoteInteger:
NeedsReanalyzing = PromoteIntegerOperand(N, i);
Changed = true;
break;
case TargetLowering::TypeExpandInteger:
NeedsReanalyzing = ExpandIntegerOperand(N, i);
Changed = true;
break;
case TargetLowering::TypeSoftenFloat:
NeedsReanalyzing = SoftenFloatOperand(N, i);
Changed = true;
break;
case TargetLowering::TypeExpandFloat:
NeedsReanalyzing = ExpandFloatOperand(N, i);
Changed = true;
break;
case TargetLowering::TypeScalarizeVector:
NeedsReanalyzing = ScalarizeVectorOperand(N, i);
Changed = true;
break;
case TargetLowering::TypeSplitVector:
NeedsReanalyzing = SplitVectorOperand(N, i);
Changed = true;
break;
case TargetLowering::TypeWidenVector:
NeedsReanalyzing = WidenVectorOperand(N, i);
Changed = true;
break;
case TargetLowering::TypePromoteFloat:
NeedsReanalyzing = PromoteFloatOperand(N, i);
Changed = true;
break;
case TargetLowering::TypeSoftPromoteHalf:
NeedsReanalyzing = SoftPromoteHalfOperand(N, i);
Changed = true;
break;
}
break;
}
if (NeedsReanalyzing) {
assert(N->getNodeId() == ReadyToProcess && "Node ID recalculated?");
N->setNodeId(NewNode);
SDNode *M = AnalyzeNewNode(N);
if (M == N)
continue;
assert(N->getNumValues() == M->getNumValues() &&
"Node morphing changed the number of results!");
for (unsigned i = 0, e = N->getNumValues(); i != e; ++i)
ReplaceValueWith(SDValue(N, i), SDValue(M, i));
assert(N->getNodeId() == NewNode && "Unexpected node state!");
continue;
}
if (i == NumOperands) {
LLVM_DEBUG(dbgs() << "Legally typed node: "; N->dump(&DAG);
dbgs() << "\n");
}
}
NodeDone:
assert(N->getNodeId() == ReadyToProcess && "Node ID recalculated?");
N->setNodeId(Processed);
for (SDNode *User : N->uses()) {
int NodeId = User->getNodeId();
if (NodeId > 0) {
User->setNodeId(NodeId-1);
if (NodeId-1 == ReadyToProcess)
Worklist.push_back(User);
continue;
}
if (NodeId == NewNode)
continue;
assert(NodeId == Unanalyzed && "Unknown node ID!");
User->setNodeId(User->getNumOperands() - 1);
if (User->getNumOperands() == 1)
Worklist.push_back(User);
}
}
#ifndef EXPENSIVE_CHECKS
if (EnableExpensiveChecks)
#endif
PerformExpensiveChecks();
DAG.setRoot(Dummy.getValue());
DAG.RemoveDeadNodes();
#ifndef NDEBUG
for (SDNode &Node : DAG.allnodes()) {
bool Failed = false;
if (!IgnoreNodeResults(&Node))
for (unsigned i = 0, NumVals = Node.getNumValues(); i < NumVals; ++i)
if (!isTypeLegal(Node.getValueType(i))) {
dbgs() << "Result type " << i << " illegal: ";
Node.dump(&DAG);
Failed = true;
}
for (unsigned i = 0, NumOps = Node.getNumOperands(); i < NumOps; ++i)
if (!IgnoreNodeResults(Node.getOperand(i).getNode()) &&
!isTypeLegal(Node.getOperand(i).getValueType())) {
dbgs() << "Operand type " << i << " illegal: ";
Node.getOperand(i).dump(&DAG);
Failed = true;
}
if (Node.getNodeId() != Processed) {
if (Node.getNodeId() == NewNode)
dbgs() << "New node not analyzed?\n";
else if (Node.getNodeId() == Unanalyzed)
dbgs() << "Unanalyzed node not noticed?\n";
else if (Node.getNodeId() > 0)
dbgs() << "Operand not processed?\n";
else if (Node.getNodeId() == ReadyToProcess)
dbgs() << "Not added to worklist?\n";
Failed = true;
}
if (Failed) {
Node.dump(&DAG); dbgs() << "\n";
llvm_unreachable(nullptr);
}
}
#endif
return Changed;
}
SDNode *DAGTypeLegalizer::AnalyzeNewNode(SDNode *N) {
if (N->getNodeId() != NewNode && N->getNodeId() != Unanalyzed)
return N;
std::vector<SDValue> NewOps;
unsigned NumProcessed = 0;
for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
SDValue OrigOp = N->getOperand(i);
SDValue Op = OrigOp;
AnalyzeNewValue(Op);
if (Op.getNode()->getNodeId() == Processed)
++NumProcessed;
if (!NewOps.empty()) {
NewOps.push_back(Op);
} else if (Op != OrigOp) {
NewOps.insert(NewOps.end(), N->op_begin(), N->op_begin() + i);
NewOps.push_back(Op);
}
}
if (!NewOps.empty()) {
SDNode *M = DAG.UpdateNodeOperands(N, NewOps);
if (M != N) {
N->setNodeId(NewNode);
if (M->getNodeId() != NewNode && M->getNodeId() != Unanalyzed)
return M;
N = M;
}
}
N->setNodeId(N->getNumOperands() - NumProcessed);
if (N->getNodeId() == ReadyToProcess)
Worklist.push_back(N);
return N;
}
void DAGTypeLegalizer::AnalyzeNewValue(SDValue &Val) {
Val.setNode(AnalyzeNewNode(Val.getNode()));
if (Val.getNode()->getNodeId() == Processed)
RemapValue(Val);
}
void DAGTypeLegalizer::RemapValue(SDValue &V) {
auto Id = getTableId(V);
V = getSDValue(Id);
}
void DAGTypeLegalizer::RemapId(TableId &Id) {
auto I = ReplacedValues.find(Id);
if (I != ReplacedValues.end()) {
assert(Id != I->second && "Id is mapped to itself.");
RemapId(I->second);
Id = I->second;
}
}
namespace {
class NodeUpdateListener : public SelectionDAG::DAGUpdateListener {
DAGTypeLegalizer &DTL;
SmallSetVector<SDNode*, 16> &NodesToAnalyze;
public:
explicit NodeUpdateListener(DAGTypeLegalizer &dtl,
SmallSetVector<SDNode*, 16> &nta)
: SelectionDAG::DAGUpdateListener(dtl.getDAG()),
DTL(dtl), NodesToAnalyze(nta) {}
void NodeDeleted(SDNode *N, SDNode *E) override {
assert(N->getNodeId() != DAGTypeLegalizer::ReadyToProcess &&
N->getNodeId() != DAGTypeLegalizer::Processed &&
"Invalid node ID for RAUW deletion!");
assert(E && "Node not replaced?");
DTL.NoteDeletion(N, E);
NodesToAnalyze.remove(N);
if (E->getNodeId() == DAGTypeLegalizer::NewNode)
NodesToAnalyze.insert(E);
}
void NodeUpdated(SDNode *N) override {
assert(N->getNodeId() != DAGTypeLegalizer::ReadyToProcess &&
N->getNodeId() != DAGTypeLegalizer::Processed &&
"Invalid node ID for RAUW deletion!");
N->setNodeId(DAGTypeLegalizer::NewNode);
NodesToAnalyze.insert(N);
}
};
}
void DAGTypeLegalizer::ReplaceValueWith(SDValue From, SDValue To) {
assert(From.getNode() != To.getNode() && "Potential legalization loop!");
AnalyzeNewValue(To);
SmallSetVector<SDNode*, 16> NodesToAnalyze;
NodeUpdateListener NUL(*this, NodesToAnalyze);
do {
auto FromId = getTableId(From);
auto ToId = getTableId(To);
if (FromId != ToId)
ReplacedValues[FromId] = ToId;
DAG.ReplaceAllUsesOfValueWith(From, To);
while (!NodesToAnalyze.empty()) {
SDNode *N = NodesToAnalyze.pop_back_val();
if (N->getNodeId() != DAGTypeLegalizer::NewNode)
continue;
SDNode *M = AnalyzeNewNode(N);
if (M != N) {
assert(M->getNodeId() != NewNode && "Analysis resulted in NewNode!");
assert(N->getNumValues() == M->getNumValues() &&
"Node morphing changed the number of results!");
for (unsigned i = 0, e = N->getNumValues(); i != e; ++i) {
SDValue OldVal(N, i);
SDValue NewVal(M, i);
if (M->getNodeId() == Processed)
RemapValue(NewVal);
auto OldValId = getTableId(OldVal);
auto NewValId = getTableId(NewVal);
DAG.ReplaceAllUsesOfValueWith(OldVal, NewVal);
if (OldValId != NewValId)
ReplacedValues[OldValId] = NewValId;
}
}
}
} while (!From.use_empty());
}
void DAGTypeLegalizer::SetPromotedInteger(SDValue Op, SDValue Result) {
assert(Result.getValueType() ==
TLI.getTypeToTransformTo(*DAG.getContext(), Op.getValueType()) &&
"Invalid type for promoted integer");
AnalyzeNewValue(Result);
auto &OpIdEntry = PromotedIntegers[getTableId(Op)];
assert((OpIdEntry == 0) && "Node is already promoted!");
OpIdEntry = getTableId(Result);
Result->setFlags(Op->getFlags());
DAG.transferDbgValues(Op, Result);
}
void DAGTypeLegalizer::SetSoftenedFloat(SDValue Op, SDValue Result) {
assert(Result.getValueType() ==
TLI.getTypeToTransformTo(*DAG.getContext(), Op.getValueType()) &&
"Invalid type for softened float");
AnalyzeNewValue(Result);
auto &OpIdEntry = SoftenedFloats[getTableId(Op)];
assert((OpIdEntry == 0) && "Node is already converted to integer!");
OpIdEntry = getTableId(Result);
}
void DAGTypeLegalizer::SetPromotedFloat(SDValue Op, SDValue Result) {
assert(Result.getValueType() ==
TLI.getTypeToTransformTo(*DAG.getContext(), Op.getValueType()) &&
"Invalid type for promoted float");
AnalyzeNewValue(Result);
auto &OpIdEntry = PromotedFloats[getTableId(Op)];
assert((OpIdEntry == 0) && "Node is already promoted!");
OpIdEntry = getTableId(Result);
}
void DAGTypeLegalizer::SetSoftPromotedHalf(SDValue Op, SDValue Result) {
assert(Result.getValueType() == MVT::i16 &&
"Invalid type for soft-promoted half");
AnalyzeNewValue(Result);
auto &OpIdEntry = SoftPromotedHalfs[getTableId(Op)];
assert((OpIdEntry == 0) && "Node is already promoted!");
OpIdEntry = getTableId(Result);
}
void DAGTypeLegalizer::SetScalarizedVector(SDValue Op, SDValue Result) {
assert(Result.getValueSizeInBits().getFixedSize() >=
Op.getScalarValueSizeInBits() &&
"Invalid type for scalarized vector");
AnalyzeNewValue(Result);
auto &OpIdEntry = ScalarizedVectors[getTableId(Op)];
assert((OpIdEntry == 0) && "Node is already scalarized!");
OpIdEntry = getTableId(Result);
}
void DAGTypeLegalizer::GetExpandedInteger(SDValue Op, SDValue &Lo,
SDValue &Hi) {
std::pair<TableId, TableId> &Entry = ExpandedIntegers[getTableId(Op)];
assert((Entry.first != 0) && "Operand isn't expanded");
Lo = getSDValue(Entry.first);
Hi = getSDValue(Entry.second);
}
void DAGTypeLegalizer::SetExpandedInteger(SDValue Op, SDValue Lo,
SDValue Hi) {
assert(Lo.getValueType() ==
TLI.getTypeToTransformTo(*DAG.getContext(), Op.getValueType()) &&
Hi.getValueType() == Lo.getValueType() &&
"Invalid type for expanded integer");
AnalyzeNewValue(Lo);
AnalyzeNewValue(Hi);
if (DAG.getDataLayout().isBigEndian()) {
DAG.transferDbgValues(Op, Hi, 0, Hi.getValueSizeInBits(), false);
DAG.transferDbgValues(Op, Lo, Hi.getValueSizeInBits(),
Lo.getValueSizeInBits());
} else {
DAG.transferDbgValues(Op, Lo, 0, Lo.getValueSizeInBits(), false);
DAG.transferDbgValues(Op, Hi, Lo.getValueSizeInBits(),
Hi.getValueSizeInBits());
}
std::pair<TableId, TableId> &Entry = ExpandedIntegers[getTableId(Op)];
assert((Entry.first == 0) && "Node already expanded");
Entry.first = getTableId(Lo);
Entry.second = getTableId(Hi);
}
void DAGTypeLegalizer::GetExpandedFloat(SDValue Op, SDValue &Lo,
SDValue &Hi) {
std::pair<TableId, TableId> &Entry = ExpandedFloats[getTableId(Op)];
assert((Entry.first != 0) && "Operand isn't expanded");
Lo = getSDValue(Entry.first);
Hi = getSDValue(Entry.second);
}
void DAGTypeLegalizer::SetExpandedFloat(SDValue Op, SDValue Lo,
SDValue Hi) {
assert(Lo.getValueType() ==
TLI.getTypeToTransformTo(*DAG.getContext(), Op.getValueType()) &&
Hi.getValueType() == Lo.getValueType() &&
"Invalid type for expanded float");
AnalyzeNewValue(Lo);
AnalyzeNewValue(Hi);
std::pair<TableId, TableId> &Entry = ExpandedFloats[getTableId(Op)];
assert((Entry.first == 0) && "Node already expanded");
Entry.first = getTableId(Lo);
Entry.second = getTableId(Hi);
}
void DAGTypeLegalizer::GetSplitVector(SDValue Op, SDValue &Lo,
SDValue &Hi) {
std::pair<TableId, TableId> &Entry = SplitVectors[getTableId(Op)];
Lo = getSDValue(Entry.first);
Hi = getSDValue(Entry.second);
assert(Lo.getNode() && "Operand isn't split");
;
}
void DAGTypeLegalizer::SetSplitVector(SDValue Op, SDValue Lo,
SDValue Hi) {
assert(Lo.getValueType().getVectorElementType() ==
Op.getValueType().getVectorElementType() &&
Lo.getValueType().getVectorElementCount() * 2 ==
Op.getValueType().getVectorElementCount() &&
Hi.getValueType() == Lo.getValueType() &&
"Invalid type for split vector");
AnalyzeNewValue(Lo);
AnalyzeNewValue(Hi);
std::pair<TableId, TableId> &Entry = SplitVectors[getTableId(Op)];
assert((Entry.first == 0) && "Node already split");
Entry.first = getTableId(Lo);
Entry.second = getTableId(Hi);
}
void DAGTypeLegalizer::SetWidenedVector(SDValue Op, SDValue Result) {
assert(Result.getValueType() ==
TLI.getTypeToTransformTo(*DAG.getContext(), Op.getValueType()) &&
"Invalid type for widened vector");
AnalyzeNewValue(Result);
auto &OpIdEntry = WidenedVectors[getTableId(Op)];
assert((OpIdEntry == 0) && "Node already widened!");
OpIdEntry = getTableId(Result);
}
SDValue DAGTypeLegalizer::BitConvertToInteger(SDValue Op) {
unsigned BitWidth = Op.getValueSizeInBits();
return DAG.getNode(ISD::BITCAST, SDLoc(Op),
EVT::getIntegerVT(*DAG.getContext(), BitWidth), Op);
}
SDValue DAGTypeLegalizer::BitConvertVectorToIntegerVector(SDValue Op) {
assert(Op.getValueType().isVector() && "Only applies to vectors!");
unsigned EltWidth = Op.getScalarValueSizeInBits();
EVT EltNVT = EVT::getIntegerVT(*DAG.getContext(), EltWidth);
auto EltCnt = Op.getValueType().getVectorElementCount();
return DAG.getNode(ISD::BITCAST, SDLoc(Op),
EVT::getVectorVT(*DAG.getContext(), EltNVT, EltCnt), Op);
}
SDValue DAGTypeLegalizer::CreateStackStoreLoad(SDValue Op,
EVT DestVT) {
SDLoc dl(Op);
Align DestAlign = DAG.getReducedAlign(DestVT, false);
Align OpAlign = DAG.getReducedAlign(Op.getValueType(), false);
Align Align = std::max(DestAlign, OpAlign);
SDValue StackPtr =
DAG.CreateStackTemporary(Op.getValueType().getStoreSize(), Align);
SDValue Store = DAG.getStore(DAG.getEntryNode(), dl, Op, StackPtr,
MachinePointerInfo(), Align);
return DAG.getLoad(DestVT, dl, Store, StackPtr, MachinePointerInfo(), Align);
}
bool DAGTypeLegalizer::CustomLowerNode(SDNode *N, EVT VT, bool LegalizeResult) {
if (TLI.getOperationAction(N->getOpcode(), VT) != TargetLowering::Custom)
return false;
SmallVector<SDValue, 8> Results;
if (LegalizeResult)
TLI.ReplaceNodeResults(N, Results, DAG);
else
TLI.LowerOperationWrapper(N, Results, DAG);
if (Results.empty())
return false;
assert(Results.size() == N->getNumValues() &&
"Custom lowering returned the wrong number of results!");
for (unsigned i = 0, e = Results.size(); i != e; ++i) {
ReplaceValueWith(SDValue(N, i), Results[i]);
}
return true;
}
bool DAGTypeLegalizer::CustomWidenLowerNode(SDNode *N, EVT VT) {
if (TLI.getOperationAction(N->getOpcode(), VT) != TargetLowering::Custom)
return false;
SmallVector<SDValue, 8> Results;
TLI.ReplaceNodeResults(N, Results, DAG);
if (Results.empty())
return false;
assert(Results.size() == N->getNumValues() &&
"Custom lowering returned the wrong number of results!");
for (unsigned i = 0, e = Results.size(); i != e; ++i) {
bool WasWidened = SDValue(N, i).getValueType() != Results[i].getValueType();
if (WasWidened)
SetWidenedVector(SDValue(N, i), Results[i]);
else
ReplaceValueWith(SDValue(N, i), Results[i]);
}
return true;
}
SDValue DAGTypeLegalizer::DisintegrateMERGE_VALUES(SDNode *N, unsigned ResNo) {
for (unsigned i = 0, e = N->getNumValues(); i != e; ++i)
if (i != ResNo)
ReplaceValueWith(SDValue(N, i), SDValue(N->getOperand(i)));
return SDValue(N->getOperand(ResNo));
}
void DAGTypeLegalizer::GetPairElements(SDValue Pair,
SDValue &Lo, SDValue &Hi) {
SDLoc dl(Pair);
EVT NVT = TLI.getTypeToTransformTo(*DAG.getContext(), Pair.getValueType());
Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, NVT, Pair,
DAG.getIntPtrConstant(0, dl));
Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, NVT, Pair,
DAG.getIntPtrConstant(1, dl));
}
SDValue DAGTypeLegalizer::JoinIntegers(SDValue Lo, SDValue Hi) {
SDLoc dlHi(Hi);
SDLoc dlLo(Lo);
EVT LVT = Lo.getValueType();
EVT HVT = Hi.getValueType();
EVT NVT = EVT::getIntegerVT(*DAG.getContext(),
LVT.getSizeInBits() + HVT.getSizeInBits());
EVT ShiftAmtVT = TLI.getShiftAmountTy(NVT, DAG.getDataLayout(), false);
Lo = DAG.getNode(ISD::ZERO_EXTEND, dlLo, NVT, Lo);
Hi = DAG.getNode(ISD::ANY_EXTEND, dlHi, NVT, Hi);
Hi = DAG.getNode(ISD::SHL, dlHi, NVT, Hi,
DAG.getConstant(LVT.getSizeInBits(), dlHi, ShiftAmtVT));
return DAG.getNode(ISD::OR, dlHi, NVT, Lo, Hi);
}
SDValue DAGTypeLegalizer::PromoteTargetBoolean(SDValue Bool, EVT ValVT) {
return TLI.promoteTargetBoolean(DAG, Bool, ValVT);
}
void DAGTypeLegalizer::SplitInteger(SDValue Op,
EVT LoVT, EVT HiVT,
SDValue &Lo, SDValue &Hi) {
SDLoc dl(Op);
assert(LoVT.getSizeInBits() + HiVT.getSizeInBits() ==
Op.getValueSizeInBits() && "Invalid integer splitting!");
Lo = DAG.getNode(ISD::TRUNCATE, dl, LoVT, Op);
unsigned ReqShiftAmountInBits =
Log2_32_Ceil(Op.getValueType().getSizeInBits());
MVT ShiftAmountTy =
TLI.getScalarShiftAmountTy(DAG.getDataLayout(), Op.getValueType());
if (ReqShiftAmountInBits > ShiftAmountTy.getSizeInBits())
ShiftAmountTy = MVT::getIntegerVT(NextPowerOf2(ReqShiftAmountInBits));
Hi = DAG.getNode(ISD::SRL, dl, Op.getValueType(), Op,
DAG.getConstant(LoVT.getSizeInBits(), dl, ShiftAmountTy));
Hi = DAG.getNode(ISD::TRUNCATE, dl, HiVT, Hi);
}
void DAGTypeLegalizer::SplitInteger(SDValue Op,
SDValue &Lo, SDValue &Hi) {
EVT HalfVT =
EVT::getIntegerVT(*DAG.getContext(), Op.getValueSizeInBits() / 2);
SplitInteger(Op, HalfVT, HalfVT, Lo, Hi);
}
bool SelectionDAG::LegalizeTypes() {
return DAGTypeLegalizer(*this).run();
}