forked from OSchip/llvm-project
[legalize-types] Clean up softening machinery.
The patch makes SoftenFloatResult/Operand logic just the same as all other legalization routines have: SoftenFloatResult() now fills the SoftenFloats map and SoftenFloatOperand() perform all needed replacements. This prevents softening mashinery from leaving stale entries in SoftenFloats map (that resulted in errors during the legalize type checking) and clarifies softening. The patch replaces https://reviews.llvm.org/D29265. Differential Revision: https://reviews.llvm.org/D31946 llvm-svn: 307053
This commit is contained in:
parent
61118e7ecd
commit
66d32c5e06
|
@ -112,15 +112,15 @@ bool DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) {
|
|||
case ISD::VAARG: R = SoftenFloatRes_VAARG(N); break;
|
||||
}
|
||||
|
||||
// If R is null, the sub-method took care of registering the result.
|
||||
if (R.getNode()) {
|
||||
if (R.getNode() && R.getNode() != N) {
|
||||
SetSoftenedFloat(SDValue(N, ResNo), R);
|
||||
ReplaceSoftenFloatResult(N, ResNo, R);
|
||||
// Return true only if the node is changed, assuming that the operands
|
||||
// are also converted when necessary.
|
||||
return true;
|
||||
}
|
||||
// Return true only if the node is changed,
|
||||
// assuming that the operands are also converted when necessary.
|
||||
|
||||
// Otherwise, return false to tell caller to scan operands.
|
||||
return R.getNode() && R.getNode() != N;
|
||||
return false;
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatRes_BITCAST(SDNode *N, unsigned ResNo) {
|
||||
|
@ -753,12 +753,17 @@ bool DAGTypeLegalizer::SoftenFloatOperand(SDNode *N, unsigned OpNo) {
|
|||
llvm_unreachable("Do not know how to soften this operator's operand!");
|
||||
|
||||
case ISD::BITCAST: Res = SoftenFloatOp_BITCAST(N); break;
|
||||
case ISD::CopyToReg: Res = SoftenFloatOp_COPY_TO_REG(N); break;
|
||||
case ISD::BR_CC: Res = SoftenFloatOp_BR_CC(N); break;
|
||||
case ISD::FABS: Res = SoftenFloatOp_FABS(N); break;
|
||||
case ISD::FCOPYSIGN: Res = SoftenFloatOp_FCOPYSIGN(N); break;
|
||||
case ISD::FNEG: Res = SoftenFloatOp_FNEG(N); break;
|
||||
case ISD::FP_EXTEND: Res = SoftenFloatOp_FP_EXTEND(N); break;
|
||||
case ISD::FP_TO_FP16: // Same as FP_ROUND for softening purposes
|
||||
case ISD::FP_ROUND: Res = SoftenFloatOp_FP_ROUND(N); break;
|
||||
case ISD::FP_TO_SINT:
|
||||
case ISD::FP_TO_UINT: Res = SoftenFloatOp_FP_TO_XINT(N); break;
|
||||
case ISD::SELECT: Res = SoftenFloatOp_SELECT(N); break;
|
||||
case ISD::SELECT_CC: Res = SoftenFloatOp_SELECT_CC(N); break;
|
||||
case ISD::SETCC: Res = SoftenFloatOp_SETCC(N); break;
|
||||
case ISD::STORE:
|
||||
|
@ -791,9 +796,9 @@ bool DAGTypeLegalizer::SoftenFloatOperand(SDNode *N, unsigned OpNo) {
|
|||
bool DAGTypeLegalizer::CanSkipSoftenFloatOperand(SDNode *N, unsigned OpNo) {
|
||||
if (!isLegalInHWReg(N->getOperand(OpNo).getValueType()))
|
||||
return false;
|
||||
// When the operand type can be kept in registers, SoftenFloatResult
|
||||
// will call ReplaceValueWith to replace all references and we can
|
||||
// skip softening this operand.
|
||||
|
||||
// When the operand type can be kept in registers there is nothing to do for
|
||||
// the following opcodes.
|
||||
switch (N->getOperand(OpNo).getOpcode()) {
|
||||
case ISD::BITCAST:
|
||||
case ISD::ConstantFP:
|
||||
|
@ -807,18 +812,12 @@ bool DAGTypeLegalizer::CanSkipSoftenFloatOperand(SDNode *N, unsigned OpNo) {
|
|||
case ISD::SELECT_CC:
|
||||
return true;
|
||||
}
|
||||
// For some opcodes, SoftenFloatResult handles all conversion of softening
|
||||
// and replacing operands, so that there is no need to soften operands
|
||||
// again, although such opcode could be scanned for other illegal operands.
|
||||
|
||||
switch (N->getOpcode()) {
|
||||
case ISD::ConstantFP:
|
||||
case ISD::CopyFromReg:
|
||||
case ISD::CopyToReg:
|
||||
case ISD::FABS:
|
||||
case ISD::FCOPYSIGN:
|
||||
case ISD::FNEG:
|
||||
case ISD::Register:
|
||||
case ISD::SELECT:
|
||||
case ISD::ConstantFP: // Leaf node.
|
||||
case ISD::CopyFromReg: // Operand is a register that we know to be left
|
||||
// unchanged by SoftenFloatResult().
|
||||
case ISD::Register: // Leaf node.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -829,6 +828,21 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_BITCAST(SDNode *N) {
|
|||
GetSoftenedFloat(N->getOperand(0)));
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_COPY_TO_REG(SDNode *N) {
|
||||
SDValue Op1 = GetSoftenedFloat(N->getOperand(1));
|
||||
SDValue Op2 = GetSoftenedFloat(N->getOperand(2));
|
||||
|
||||
if (Op1 == N->getOperand(1) && Op2 == N->getOperand(2))
|
||||
return SDValue();
|
||||
|
||||
if (N->getNumOperands() == 3)
|
||||
return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), Op1, Op2), 0);
|
||||
|
||||
return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), Op1, Op2,
|
||||
N->getOperand(3)),
|
||||
0);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_FP_EXTEND(SDNode *N) {
|
||||
// If we get here, the result must be legal but the source illegal.
|
||||
EVT SVT = N->getOperand(0).getValueType();
|
||||
|
@ -884,6 +898,34 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_BR_CC(SDNode *N) {
|
|||
0);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_FABS(SDNode *N) {
|
||||
SDValue Op = GetSoftenedFloat(N->getOperand(0));
|
||||
|
||||
if (Op == N->getOperand(0))
|
||||
return SDValue();
|
||||
|
||||
return SDValue(DAG.UpdateNodeOperands(N, Op), 0);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_FCOPYSIGN(SDNode *N) {
|
||||
SDValue Op0 = GetSoftenedFloat(N->getOperand(0));
|
||||
SDValue Op1 = GetSoftenedFloat(N->getOperand(1));
|
||||
|
||||
if (Op0 == N->getOperand(0) && Op1 == N->getOperand(1))
|
||||
return SDValue();
|
||||
|
||||
return SDValue(DAG.UpdateNodeOperands(N, Op0, Op1), 0);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_FNEG(SDNode *N) {
|
||||
SDValue Op = GetSoftenedFloat(N->getOperand(0));
|
||||
|
||||
if (Op == N->getOperand(0))
|
||||
return SDValue();
|
||||
|
||||
return SDValue(DAG.UpdateNodeOperands(N, Op), 0);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_FP_TO_XINT(SDNode *N) {
|
||||
bool Signed = N->getOpcode() == ISD::FP_TO_SINT;
|
||||
EVT SVT = N->getOperand(0).getValueType();
|
||||
|
@ -913,6 +955,17 @@ SDValue DAGTypeLegalizer::SoftenFloatOp_FP_TO_XINT(SDNode *N) {
|
|||
return DAG.getNode(ISD::TRUNCATE, dl, RVT, Res);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_SELECT(SDNode *N) {
|
||||
SDValue Op1 = GetSoftenedFloat(N->getOperand(1));
|
||||
SDValue Op2 = GetSoftenedFloat(N->getOperand(2));
|
||||
|
||||
if (Op1 == N->getOperand(1) && Op2 == N->getOperand(2))
|
||||
return SDValue();
|
||||
|
||||
return SDValue(DAG.UpdateNodeOperands(N, N->getOperand(0), Op1, Op2),
|
||||
0);
|
||||
}
|
||||
|
||||
SDValue DAGTypeLegalizer::SoftenFloatOp_SELECT_CC(SDNode *N) {
|
||||
SDValue NewLHS = N->getOperand(0), NewRHS = N->getOperand(1);
|
||||
ISD::CondCode CCCode = cast<CondCodeSDNode>(N->getOperand(4))->get();
|
||||
|
|
|
@ -80,6 +80,7 @@ void DAGTypeLegalizer::PerformExpensiveChecks() {
|
|||
|
||||
for (unsigned i = 0, e = Node.getNumValues(); i != e; ++i) {
|
||||
SDValue Res(&Node, i);
|
||||
EVT VT = Res.getValueType();
|
||||
bool Failed = false;
|
||||
|
||||
unsigned Mapped = 0;
|
||||
|
@ -129,13 +130,17 @@ void DAGTypeLegalizer::PerformExpensiveChecks() {
|
|||
dbgs() << "Unprocessed value in a map!";
|
||||
Failed = true;
|
||||
}
|
||||
} else if (isTypeLegal(Res.getValueType()) || IgnoreNodeResults(&Node)) {
|
||||
} else if (isTypeLegal(VT) || IgnoreNodeResults(&Node)) {
|
||||
if (Mapped > 1) {
|
||||
dbgs() << "Value with legal type was transformed!";
|
||||
Failed = true;
|
||||
}
|
||||
} else {
|
||||
if (Mapped == 0) {
|
||||
// If the value can be kept in HW registers, softening machinery can
|
||||
// leave it unchanged and don't put it to any map.
|
||||
if (Mapped == 0 &&
|
||||
!(getTypeAction(VT) == TargetLowering::TypeSoftenFloat &&
|
||||
isLegalInHWReg(VT))) {
|
||||
dbgs() << "Processed value not in any map!";
|
||||
Failed = true;
|
||||
} else if (Mapped & (Mapped - 1)) {
|
||||
|
@ -331,11 +336,6 @@ ScanOperands:
|
|||
if (NeedsReanalyzing) {
|
||||
assert(N->getNodeId() == ReadyToProcess && "Node ID recalculated?");
|
||||
|
||||
// Remove any result values from SoftenedFloats as N will be revisited
|
||||
// again.
|
||||
for (unsigned i = 0, NumResults = N->getNumValues(); i < NumResults; ++i)
|
||||
SoftenedFloats.erase(SDValue(N, i));
|
||||
|
||||
N->setNodeId(NewNode);
|
||||
// Recompute the NodeId and correct processed operands, adding the node to
|
||||
// the worklist if ready.
|
||||
|
@ -754,8 +754,6 @@ void DAGTypeLegalizer::ReplaceValueWith(SDValue From, SDValue To) {
|
|||
// new uses of From due to CSE. If this happens, replace the new uses of
|
||||
// From with To.
|
||||
} while (!From.use_empty());
|
||||
|
||||
SoftenedFloats.erase(From);
|
||||
}
|
||||
|
||||
void DAGTypeLegalizer::SetPromotedInteger(SDValue Op, SDValue Result) {
|
||||
|
|
|
@ -416,16 +416,6 @@ private:
|
|||
}
|
||||
void SetSoftenedFloat(SDValue Op, SDValue Result);
|
||||
|
||||
// Call ReplaceValueWith(SDValue(N, ResNo), Res) if necessary.
|
||||
void ReplaceSoftenFloatResult(SDNode *N, unsigned ResNo, SDValue &NewRes) {
|
||||
// When the result type can be kept in HW registers, the converted
|
||||
// NewRes node could have the same type. We can save the effort in
|
||||
// cloning every user of N in SoftenFloatOperand or other legalization functions,
|
||||
// by calling ReplaceValueWith here to update all users.
|
||||
if (NewRes.getNode() != N && isLegalInHWReg(N->getValueType(ResNo)))
|
||||
ReplaceValueWith(SDValue(N, ResNo), NewRes);
|
||||
}
|
||||
|
||||
// Convert Float Results to Integer for Non-HW-supported Operations.
|
||||
bool SoftenFloatResult(SDNode *N, unsigned ResNo);
|
||||
SDValue SoftenFloatRes_MERGE_VALUES(SDNode *N, unsigned ResNo);
|
||||
|
@ -471,17 +461,23 @@ private:
|
|||
SDValue SoftenFloatRes_XINT_TO_FP(SDNode *N);
|
||||
|
||||
// Return true if we can skip softening the given operand or SDNode because
|
||||
// it was soften before by SoftenFloatResult and references to the operand
|
||||
// were replaced by ReplaceValueWith.
|
||||
// either it was soften before by SoftenFloatResult and references to the
|
||||
// operand were replaced by ReplaceValueWith or it's value type is legal in HW
|
||||
// registers and the operand can be left unchanged.
|
||||
bool CanSkipSoftenFloatOperand(SDNode *N, unsigned OpNo);
|
||||
|
||||
// Convert Float Operand to Integer for Non-HW-supported Operations.
|
||||
bool SoftenFloatOperand(SDNode *N, unsigned OpNo);
|
||||
SDValue SoftenFloatOp_BITCAST(SDNode *N);
|
||||
SDValue SoftenFloatOp_COPY_TO_REG(SDNode *N);
|
||||
SDValue SoftenFloatOp_BR_CC(SDNode *N);
|
||||
SDValue SoftenFloatOp_FABS(SDNode *N);
|
||||
SDValue SoftenFloatOp_FCOPYSIGN(SDNode *N);
|
||||
SDValue SoftenFloatOp_FNEG(SDNode *N);
|
||||
SDValue SoftenFloatOp_FP_EXTEND(SDNode *N);
|
||||
SDValue SoftenFloatOp_FP_ROUND(SDNode *N);
|
||||
SDValue SoftenFloatOp_FP_TO_XINT(SDNode *N);
|
||||
SDValue SoftenFloatOp_SELECT(SDNode *N);
|
||||
SDValue SoftenFloatOp_SELECT_CC(SDNode *N);
|
||||
SDValue SoftenFloatOp_SETCC(SDNode *N);
|
||||
SDValue SoftenFloatOp_STORE(SDNode *N, unsigned OpNo);
|
||||
|
|
|
@ -57,7 +57,7 @@ void DAGTypeLegalizer::ExpandRes_BITCAST(SDNode *N, SDValue &Lo, SDValue &Hi) {
|
|||
// Expand the floating point operand only if it was converted to integers.
|
||||
// Otherwise, it is a legal type like f128 that can be saved in a register.
|
||||
auto SoftenedOp = GetSoftenedFloat(InOp);
|
||||
if (SoftenedOp == InOp)
|
||||
if (isLegalInHWReg(SoftenedOp.getValueType()))
|
||||
break;
|
||||
SplitInteger(SoftenedOp, Lo, Hi);
|
||||
Lo = DAG.getNode(ISD::BITCAST, dl, NOutVT, Lo);
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
; RUN: llc < %s -mtriple=x86_64-linux-android -mattr=+mmx -enable-legalize-types-checking | FileCheck %s
|
||||
;
|
||||
; D31946
|
||||
; Check that we dont end up with the ""LLVM ERROR: Cannot select" error.
|
||||
; Additionally ensure that the output code actually put fp128 values in SSE registers.
|
||||
|
||||
declare fp128 @llvm.fabs.f128(fp128)
|
||||
declare fp128 @llvm.copysign.f128(fp128, fp128)
|
||||
|
||||
define fp128 @TestSelect(fp128 %a, fp128 %b) {
|
||||
%cmp = fcmp ogt fp128 %a, %b
|
||||
%sub = fsub fp128 %a, %b
|
||||
%res = select i1 %cmp, fp128 %sub, fp128 0xL00000000000000000000000000000000
|
||||
ret fp128 %res
|
||||
; CHECK-LABEL: TestSelect:
|
||||
; CHECK movaps 16(%rsp), %xmm1
|
||||
; CHECK-NEXT callq __subtf3
|
||||
; CHECK-NEXT testl %ebx, %ebx
|
||||
; CHECK-NEXT jg .LBB0_2
|
||||
; CHECK-NEXT # BB#1:
|
||||
; CHECK-NEXT movaps .LCPI0_0(%rip), %xmm0
|
||||
; CHECK-NEXT .LBB0_2:
|
||||
; CHECK-NEXT addq $32, %rsp
|
||||
; CHECK-NEXT popq %rbx
|
||||
; CHECK-NEXT retq
|
||||
}
|
||||
|
||||
define fp128 @TestFabs(fp128 %a) {
|
||||
%res = call fp128 @llvm.fabs.f128(fp128 %a)
|
||||
ret fp128 %res
|
||||
; CHECK-LABEL: TestFabs:
|
||||
; CHECK andps .LCPI1_0(%rip), %xmm0
|
||||
; CHECK-NEXT retq
|
||||
}
|
||||
|
||||
define fp128 @TestCopysign(fp128 %a, fp128 %b) {
|
||||
%res = call fp128 @llvm.copysign.f128(fp128 %a, fp128 %b)
|
||||
ret fp128 %res
|
||||
; CHECK-LABEL: TestCopysign:
|
||||
; CHECK andps .LCPI2_1(%rip), %xmm0
|
||||
; CHECK-NEXT orps %xmm1, %xmm0
|
||||
; CHECK-NEXT retq
|
||||
}
|
||||
|
||||
define fp128 @TestFneg(fp128 %a) {
|
||||
%mul = fmul fp128 %a, %a
|
||||
%res = fsub fp128 0xL00000000000000008000000000000000, %mul
|
||||
ret fp128 %res
|
||||
; CHECK-LABEL: TestFneg:
|
||||
; CHECK movaps %xmm0, %xmm1
|
||||
; CHECK-NEXT callq __multf3
|
||||
; CHECK-NEXT xorps .LCPI3_0(%rip), %xmm0
|
||||
; CHECK-NEXT popq %rax
|
||||
; CHECK-NEXT retq
|
||||
}
|
Loading…
Reference in New Issue