Skip to content

Commit

Permalink
[legalize-types] Clean up softening machinery.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
ayartsev7 committed Jul 4, 2017
1 parent 61118e7 commit 66d32c5
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 42 deletions.
93 changes: 73 additions & 20 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand All @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
16 changes: 7 additions & 9 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -331,11 +336,6 @@ bool DAGTypeLegalizer::run() {
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.
Expand Down Expand Up @@ -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) {
Expand Down
20 changes: 8 additions & 12 deletions llvm/lib/CodeGen/SelectionDAG/LegalizeTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -416,16 +416,6 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
}
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);
Expand Down Expand Up @@ -471,17 +461,23 @@ class LLVM_LIBRARY_VISIBILITY DAGTypeLegalizer {
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);
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
55 changes: 55 additions & 0 deletions llvm/test/CodeGen/X86/soft-fp-legal-in-HW-reg.ll
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 66d32c5

Please sign in to comment.