Skip to content

Commit 0664c25

Browse files
[ConstantTime][LLVM] Add llvm.ct.select intrinsic with generic SelectionDAG lowering
1 parent ed45c05 commit 0664c25

19 files changed

+1498
-14
lines changed

llvm/include/llvm/CodeGen/ISDOpcodes.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,10 @@ enum NodeType {
783783
/// i1 then the high bits must conform to getBooleanContents.
784784
SELECT,
785785

786+
/// Constant-time Select, implemented with CMOV instruction. This is used to
787+
/// implement constant-time select.
788+
CTSELECT,
789+
786790
/// Select with a vector condition (op #0) and two vector operands (ops #1
787791
/// and #2), returning a vector result. All vectors have the same length.
788792
/// Much like the scalar select and setcc, each bit in the condition selects

llvm/include/llvm/CodeGen/SelectionDAG.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,13 @@ class SelectionDAG {
13521352
return getNode(Opcode, DL, VT, Cond, LHS, RHS, Flags);
13531353
}
13541354

1355+
SDValue getCTSelect(const SDLoc &DL, EVT VT, SDValue Cond, SDValue LHS,
1356+
SDValue RHS, SDNodeFlags Flags = SDNodeFlags()) {
1357+
assert(LHS.getValueType() == VT && RHS.getValueType() == VT &&
1358+
"Cannot use select on differing types");
1359+
return getNode(ISD::CTSELECT, DL, VT, Cond, LHS, RHS, Flags);
1360+
}
1361+
13551362
/// Helper function to make it easier to build SelectCC's if you just have an
13561363
/// ISD::CondCode instead of an SDValue.
13571364
SDValue getSelectCC(const SDLoc &DL, SDValue LHS, SDValue RHS, SDValue True,

llvm/include/llvm/CodeGen/SelectionDAGNodes.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,6 +435,9 @@ struct SDNodeFlags {
435435
NonNeg | NoNaNs | NoInfs | SameSign | InBounds,
436436
FastMathFlags = NoNaNs | NoInfs | NoSignedZeros | AllowReciprocal |
437437
AllowContract | ApproximateFuncs | AllowReassociation,
438+
439+
// Flag for disabling optimization
440+
NoMerge = 1 << 15,
438441
};
439442

440443
/// Default constructor turns off all optimization flags.
@@ -486,7 +489,6 @@ struct SDNodeFlags {
486489
bool hasNoFPExcept() const { return Flags & NoFPExcept; }
487490
bool hasUnpredictable() const { return Flags & Unpredictable; }
488491
bool hasInBounds() const { return Flags & InBounds; }
489-
490492
bool operator==(const SDNodeFlags &Other) const {
491493
return Flags == Other.Flags;
492494
}

llvm/include/llvm/CodeGen/TargetLowering.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -242,11 +242,15 @@ class LLVM_ABI TargetLoweringBase {
242242

243243
/// Enum that describes what type of support for selects the target has.
244244
enum SelectSupportKind {
245-
ScalarValSelect, // The target supports scalar selects (ex: cmov).
246-
ScalarCondVectorVal, // The target supports selects with a scalar condition
247-
// and vector values (ex: cmov).
248-
VectorMaskSelect // The target supports vector selects with a vector
249-
// mask (ex: x86 blends).
245+
ScalarValSelect, // The target supports scalar selects (ex: cmov).
246+
ScalarCondVectorVal, // The target supports selects with a scalar condition
247+
// and vector values (ex: cmov).
248+
VectorMaskSelect, // The target supports vector selects with a vector
249+
// mask (ex: x86 blends).
250+
CtSelect, // The target implements a custom constant-time select.
251+
ScalarCondVectorValCtSelect, // The target supports selects with a scalar
252+
// condition and vector values.
253+
VectorMaskValCtSelect, // The target supports vector selects with a vector
250254
};
251255

252256
/// Enum that specifies what an atomic load/AtomicRMWInst is expanded
@@ -476,8 +480,8 @@ class LLVM_ABI TargetLoweringBase {
476480
MachineMemOperand::Flags
477481
getVPIntrinsicMemOperandFlags(const VPIntrinsic &VPIntrin) const;
478482

479-
virtual bool isSelectSupported(SelectSupportKind /*kind*/) const {
480-
return true;
483+
virtual bool isSelectSupported(SelectSupportKind kind) const {
484+
return kind != CtSelect;
481485
}
482486

483487
/// Return true if the @llvm.get.active.lane.mask intrinsic should be expanded

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1825,6 +1825,13 @@ def int_coro_subfn_addr : DefaultAttrsIntrinsic<
18251825
[IntrReadMem, IntrArgMemOnly, ReadOnly<ArgIndex<0>>,
18261826
NoCapture<ArgIndex<0>>]>;
18271827

1828+
///===-------------------------- Constant Time Intrinsics --------------------------===//
1829+
//
1830+
// Intrinsic to support constant time select
1831+
def int_ct_select : DefaultAttrsIntrinsic<[llvm_any_ty],
1832+
[llvm_i1_ty, LLVMMatchType<0>, LLVMMatchType<0>],
1833+
[IntrWriteMem, IntrWillReturn, NoUndef<RetIndex>]>;
1834+
18281835
///===-------------------------- Other Intrinsics --------------------------===//
18291836
//
18301837
// TODO: We should introduce a new memory kind fo traps (and other side effects

llvm/include/llvm/Target/TargetSelectionDAG.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,10 @@ def SDTSelect : SDTypeProfile<1, 3, [ // select
214214
SDTCisInt<1>, SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3>
215215
]>;
216216

217+
def SDTCtSelect : SDTypeProfile<1, 3, [ // ctselect
218+
SDTCisInt<1>, SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3>
219+
]>;
220+
217221
def SDTVSelect : SDTypeProfile<1, 3, [ // vselect
218222
SDTCisVec<0>, SDTCisInt<1>, SDTCisSameAs<0, 2>, SDTCisSameAs<2, 3>, SDTCisSameNumEltsAs<0, 1>
219223
]>;
@@ -717,6 +721,7 @@ def reset_fpmode : SDNode<"ISD::RESET_FPMODE", SDTNone, [SDNPHasChain]>;
717721

718722
def setcc : SDNode<"ISD::SETCC" , SDTSetCC>;
719723
def select : SDNode<"ISD::SELECT" , SDTSelect>;
724+
def ctselect : SDNode<"ISD::CTSELECT" , SDTCtSelect>;
720725
def vselect : SDNode<"ISD::VSELECT" , SDTVSelect>;
721726
def selectcc : SDNode<"ISD::SELECT_CC" , SDTSelectCC>;
722727

llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,7 @@ namespace {
484484
SDValue visitCTTZ_ZERO_UNDEF(SDNode *N);
485485
SDValue visitCTPOP(SDNode *N);
486486
SDValue visitSELECT(SDNode *N);
487+
SDValue visitCTSELECT(SDNode *N);
487488
SDValue visitVSELECT(SDNode *N);
488489
SDValue visitVP_SELECT(SDNode *N);
489490
SDValue visitSELECT_CC(SDNode *N);
@@ -1898,6 +1899,7 @@ void DAGCombiner::Run(CombineLevel AtLevel) {
18981899
}
18991900

19001901
SDValue DAGCombiner::visit(SDNode *N) {
1902+
19011903
// clang-format off
19021904
switch (N->getOpcode()) {
19031905
default: break;
@@ -1968,6 +1970,7 @@ SDValue DAGCombiner::visit(SDNode *N) {
19681970
case ISD::CTTZ_ZERO_UNDEF: return visitCTTZ_ZERO_UNDEF(N);
19691971
case ISD::CTPOP: return visitCTPOP(N);
19701972
case ISD::SELECT: return visitSELECT(N);
1973+
case ISD::CTSELECT: return visitCTSELECT(N);
19711974
case ISD::VSELECT: return visitVSELECT(N);
19721975
case ISD::SELECT_CC: return visitSELECT_CC(N);
19731976
case ISD::SETCC: return visitSETCC(N);
@@ -6032,6 +6035,7 @@ static SDValue isSaturatingMinMax(SDValue N0, SDValue N1, SDValue N2,
60326035
N0CC = cast<CondCodeSDNode>(N0.getOperand(4))->get();
60336036
break;
60346037
case ISD::SELECT:
6038+
case ISD::CTSELECT:
60356039
case ISD::VSELECT:
60366040
if (N0.getOperand(0).getOpcode() != ISD::SETCC)
60376041
return SDValue();
@@ -12184,8 +12188,9 @@ template <class MatchContextClass>
1218412188
static SDValue foldBoolSelectToLogic(SDNode *N, const SDLoc &DL,
1218512189
SelectionDAG &DAG) {
1218612190
assert((N->getOpcode() == ISD::SELECT || N->getOpcode() == ISD::VSELECT ||
12187-
N->getOpcode() == ISD::VP_SELECT) &&
12188-
"Expected a (v)(vp.)select");
12191+
N->getOpcode() == ISD::VP_SELECT ||
12192+
N->getOpcode() == ISD::CTSELECT) &&
12193+
"Expected a (v)(vp.)(ct) select");
1218912194
SDValue Cond = N->getOperand(0);
1219012195
SDValue T = N->getOperand(1), F = N->getOperand(2);
1219112196
EVT VT = N->getValueType(0);
@@ -12547,6 +12552,109 @@ SDValue DAGCombiner::visitSELECT(SDNode *N) {
1254712552
return SDValue();
1254812553
}
1254912554

12555+
SDValue DAGCombiner::visitCTSELECT(SDNode *N) {
12556+
SDValue N0 = N->getOperand(0);
12557+
SDValue N1 = N->getOperand(1);
12558+
SDValue N2 = N->getOperand(2);
12559+
EVT VT = N->getValueType(0);
12560+
EVT VT0 = N0.getValueType();
12561+
SDLoc DL(N);
12562+
SDNodeFlags Flags = N->getFlags();
12563+
12564+
if (SDValue V = foldBoolSelectToLogic<EmptyMatchContext>(N, DL, DAG))
12565+
return V;
12566+
12567+
// ctselect (not Cond), N1, N2 -> ctselect Cond, N2, N1
12568+
if (SDValue F = extractBooleanFlip(N0, DAG, TLI, false)) {
12569+
SDValue SelectOp = DAG.getNode(ISD::CTSELECT, DL, VT, F, N2, N1);
12570+
SelectOp->setFlags(Flags);
12571+
return SelectOp;
12572+
}
12573+
12574+
if (VT0 == MVT::i1) {
12575+
// The code in this block deals with the following 2 equivalences:
12576+
// select(C0|C1, x, y) <=> select(C0, x, select(C1, x, y))
12577+
// select(C0&C1, x, y) <=> select(C0, select(C1, x, y), y)
12578+
// The target can specify its preferred form with the
12579+
// shouldNormalizeToSelectSequence() callback. However we always transform
12580+
// to the right anyway if we find the inner select exists in the DAG anyway
12581+
// and we always transform to the left side if we know that we can further
12582+
// optimize the combination of the conditions.
12583+
bool normalizeToSequence =
12584+
TLI.shouldNormalizeToSelectSequence(*DAG.getContext(), VT);
12585+
// ctselect (and Cond0, Cond1), X, Y
12586+
// -> ctselect Cond0, (ctselect Cond1, X, Y), Y
12587+
if (N0->getOpcode() == ISD::AND && N0->hasOneUse()) {
12588+
SDValue Cond0 = N0->getOperand(0);
12589+
SDValue Cond1 = N0->getOperand(1);
12590+
SDValue InnerSelect = DAG.getNode(ISD::CTSELECT, DL, N1.getValueType(),
12591+
Cond1, N1, N2, Flags);
12592+
if (normalizeToSequence || !InnerSelect.use_empty())
12593+
return DAG.getNode(ISD::CTSELECT, DL, N1.getValueType(), Cond0,
12594+
InnerSelect, N2, Flags);
12595+
// Cleanup on failure.
12596+
if (InnerSelect.use_empty())
12597+
recursivelyDeleteUnusedNodes(InnerSelect.getNode());
12598+
}
12599+
// ctselect (or Cond0, Cond1), X, Y -> ctselect Cond0, X, (ctselect Cond1,
12600+
// X, Y)
12601+
if (N0->getOpcode() == ISD::OR && N0->hasOneUse()) {
12602+
SDValue Cond0 = N0->getOperand(0);
12603+
SDValue Cond1 = N0->getOperand(1);
12604+
SDValue InnerSelect = DAG.getNode(ISD::CTSELECT, DL, N1.getValueType(),
12605+
Cond1, N1, N2, Flags);
12606+
if (normalizeToSequence || !InnerSelect.use_empty())
12607+
return DAG.getNode(ISD::CTSELECT, DL, N1.getValueType(), Cond0, N1,
12608+
InnerSelect, Flags);
12609+
// Cleanup on failure.
12610+
if (InnerSelect.use_empty())
12611+
recursivelyDeleteUnusedNodes(InnerSelect.getNode());
12612+
}
12613+
12614+
// ctselect Cond0, (ctselect Cond1, X, Y), Y -> ctselect (and Cond0, Cond1),
12615+
// X, Y
12616+
if (N1->getOpcode() == ISD::CTSELECT && N1->hasOneUse()) {
12617+
SDValue N1_0 = N1->getOperand(0);
12618+
SDValue N1_1 = N1->getOperand(1);
12619+
SDValue N1_2 = N1->getOperand(2);
12620+
if (N1_2 == N2 && N0.getValueType() == N1_0.getValueType()) {
12621+
// Create the actual and node if we can generate good code for it.
12622+
if (!normalizeToSequence) {
12623+
SDValue And = DAG.getNode(ISD::AND, DL, N0.getValueType(), N0, N1_0);
12624+
return DAG.getNode(ISD::CTSELECT, DL, N1.getValueType(), And, N1_1,
12625+
N2, Flags);
12626+
}
12627+
// Otherwise see if we can optimize the "and" to a better pattern.
12628+
if (SDValue Combined = visitANDLike(N0, N1_0, N)) {
12629+
return DAG.getNode(ISD::CTSELECT, DL, N1.getValueType(), Combined,
12630+
N1_1, N2, Flags);
12631+
}
12632+
}
12633+
}
12634+
// ctselect Cond0, X, (ctselect Cond1, X, Y) -> ctselect (or Cond0, Cond1),
12635+
// X, Y
12636+
if (N2->getOpcode() == ISD::CTSELECT && N2->hasOneUse()) {
12637+
SDValue N2_0 = N2->getOperand(0);
12638+
SDValue N2_1 = N2->getOperand(1);
12639+
SDValue N2_2 = N2->getOperand(2);
12640+
if (N2_1 == N1 && N0.getValueType() == N2_0.getValueType()) {
12641+
// Create the actual or node if we can generate good code for it.
12642+
if (!normalizeToSequence) {
12643+
SDValue Or = DAG.getNode(ISD::OR, DL, N0.getValueType(), N0, N2_0);
12644+
return DAG.getNode(ISD::CTSELECT, DL, N1.getValueType(), Or, N1, N2_2,
12645+
Flags);
12646+
}
12647+
// Otherwise see if we can optimize to a better pattern.
12648+
if (SDValue Combined = visitORLike(N0, N2_0, DL))
12649+
return DAG.getNode(ISD::CTSELECT, DL, N1.getValueType(), Combined, N1,
12650+
N2_2, Flags);
12651+
}
12652+
}
12653+
}
12654+
12655+
return SDValue();
12656+
}
12657+
1255012658
// This function assumes all the vselect's arguments are CONCAT_VECTOR
1255112659
// nodes and that the condition is a BV of ConstantSDNodes (or undefs).
1255212660
static SDValue ConvertSelectToConcatVector(SDNode *N, SelectionDAG &DAG) {

llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4136,6 +4136,40 @@ bool SelectionDAGLegalize::ExpandNode(SDNode *Node) {
41364136
}
41374137
Results.push_back(Tmp1);
41384138
break;
4139+
case ISD::CTSELECT: {
4140+
Tmp1 = Node->getOperand(0);
4141+
Tmp2 = Node->getOperand(1);
4142+
Tmp3 = Node->getOperand(2);
4143+
EVT VT = Tmp2.getValueType();
4144+
if (VT.isVector()) {
4145+
SmallVector<SDValue> Elements;
4146+
unsigned NumElements = VT.getVectorNumElements();
4147+
EVT ScalarVT = VT.getScalarType();
4148+
for (unsigned Idx = 0; Idx < NumElements; ++Idx) {
4149+
SDValue IdxVal = DAG.getConstant(Idx, dl, MVT::i64);
4150+
SDValue TVal = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, ScalarVT, Tmp2, IdxVal);
4151+
SDValue FVal = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, dl, ScalarVT, Tmp3, IdxVal);
4152+
Elements.push_back(DAG.getCTSelect(dl, ScalarVT, Tmp1, TVal, FVal, Node->getFlags()));
4153+
}
4154+
Tmp1 = DAG.getBuildVector(VT, dl, Elements);
4155+
} else if (VT.isFloatingPoint()) {
4156+
EVT IntegerVT = EVT::getIntegerVT(*DAG.getContext(), VT.getSizeInBits());
4157+
Tmp2 = DAG.getBitcast(IntegerVT, Tmp2);
4158+
Tmp3 = DAG.getBitcast(IntegerVT, Tmp3);
4159+
Tmp1 = DAG.getBitcast(VT, DAG.getCTSelect(dl, IntegerVT, Tmp1, Tmp2, Tmp3, Node->getFlags()));
4160+
} else {
4161+
assert(VT.isInteger());
4162+
EVT HalfVT = VT.getHalfSizedIntegerVT(*DAG.getContext());
4163+
auto [Tmp2Lo, Tmp2Hi] = DAG.SplitScalar(Tmp2, dl, HalfVT, HalfVT);
4164+
auto [Tmp3Lo, Tmp3Hi] = DAG.SplitScalar(Tmp3, dl, HalfVT, HalfVT);
4165+
SDValue ResLo = DAG.getCTSelect(dl, HalfVT, Tmp1, Tmp2Lo, Tmp3Lo, Node->getFlags());
4166+
SDValue ResHi = DAG.getCTSelect(dl, HalfVT, Tmp1, Tmp2Hi, Tmp3Hi, Node->getFlags());
4167+
Tmp1 = DAG.getNode(ISD::BUILD_PAIR, dl, VT, ResLo, ResHi);
4168+
Tmp1->setFlags(Node->getFlags());
4169+
}
4170+
Results.push_back(Tmp1);
4171+
break;
4172+
}
41394173
case ISD::BR_JT: {
41404174
SDValue Chain = Node->getOperand(0);
41414175
SDValue Table = Node->getOperand(1);
@@ -5474,7 +5508,8 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node) {
54745508
Results.push_back(DAG.getNode(ISD::TRUNCATE, dl, OVT, Tmp2));
54755509
break;
54765510
}
5477-
case ISD::SELECT: {
5511+
case ISD::SELECT:
5512+
case ISD::CTSELECT: {
54785513
unsigned ExtOp, TruncOp;
54795514
if (Node->getValueType(0).isVector() ||
54805515
Node->getValueType(0).getSizeInBits() == NVT.getSizeInBits()) {
@@ -5492,7 +5527,8 @@ void SelectionDAGLegalize::PromoteNode(SDNode *Node) {
54925527
Tmp2 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(1));
54935528
Tmp3 = DAG.getNode(ExtOp, dl, NVT, Node->getOperand(2));
54945529
// Perform the larger operation, then round down.
5495-
Tmp1 = DAG.getSelect(dl, NVT, Tmp1, Tmp2, Tmp3);
5530+
Tmp1 = DAG.getNode(Node->getOpcode(), dl, NVT, Tmp1, Tmp2, Tmp3);
5531+
Tmp1->setFlags(Node->getFlags());
54965532
if (TruncOp != ISD::FP_ROUND)
54975533
Tmp1 = DAG.getNode(TruncOp, dl, Node->getValueType(0), Tmp1);
54985534
else

llvm/lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ void DAGTypeLegalizer::SoftenFloatResult(SDNode *N, unsigned ResNo) {
159159
case ISD::ATOMIC_LOAD: R = SoftenFloatRes_ATOMIC_LOAD(N); break;
160160
case ISD::ATOMIC_SWAP: R = BitcastToInt_ATOMIC_SWAP(N); break;
161161
case ISD::SELECT: R = SoftenFloatRes_SELECT(N); break;
162+
case ISD::CTSELECT: R = SoftenFloatRes_CTSELECT(N); break;
162163
case ISD::SELECT_CC: R = SoftenFloatRes_SELECT_CC(N); break;
163164
case ISD::FREEZE: R = SoftenFloatRes_FREEZE(N); break;
164165
case ISD::STRICT_SINT_TO_FP:
@@ -1041,6 +1042,13 @@ SDValue DAGTypeLegalizer::SoftenFloatRes_SELECT(SDNode *N) {
10411042
LHS.getValueType(), N->getOperand(0), LHS, RHS);
10421043
}
10431044

1045+
SDValue DAGTypeLegalizer::SoftenFloatRes_CTSELECT(SDNode *N) {
1046+
SDValue LHS = GetSoftenedFloat(N->getOperand(1));
1047+
SDValue RHS = GetSoftenedFloat(N->getOperand(2));
1048+
return DAG.getCTSelect(SDLoc(N), LHS.getValueType(), N->getOperand(0), LHS,
1049+
RHS);
1050+
}
1051+
10441052
SDValue DAGTypeLegalizer::SoftenFloatRes_SELECT_CC(SDNode *N) {
10451053
SDValue LHS = GetSoftenedFloat(N->getOperand(2));
10461054
SDValue RHS = GetSoftenedFloat(N->getOperand(3));
@@ -1561,6 +1569,7 @@ void DAGTypeLegalizer::ExpandFloatResult(SDNode *N, unsigned ResNo) {
15611569
case ISD::POISON:
15621570
case ISD::UNDEF: SplitRes_UNDEF(N, Lo, Hi); break;
15631571
case ISD::SELECT: SplitRes_Select(N, Lo, Hi); break;
1572+
case ISD::CTSELECT: SplitRes_Select(N, Lo, Hi); break;
15641573
case ISD::SELECT_CC: SplitRes_SELECT_CC(N, Lo, Hi); break;
15651574

15661575
case ISD::MERGE_VALUES: ExpandRes_MERGE_VALUES(N, ResNo, Lo, Hi); break;
@@ -2917,6 +2926,9 @@ void DAGTypeLegalizer::PromoteFloatResult(SDNode *N, unsigned ResNo) {
29172926
R = PromoteFloatRes_ATOMIC_LOAD(N);
29182927
break;
29192928
case ISD::SELECT: R = PromoteFloatRes_SELECT(N); break;
2929+
case ISD::CTSELECT:
2930+
R = PromoteFloatRes_SELECT(N);
2931+
break;
29202932
case ISD::SELECT_CC: R = PromoteFloatRes_SELECT_CC(N); break;
29212933

29222934
case ISD::SINT_TO_FP:
@@ -3219,7 +3231,7 @@ SDValue DAGTypeLegalizer::PromoteFloatRes_SELECT(SDNode *N) {
32193231
SDValue TrueVal = GetPromotedFloat(N->getOperand(1));
32203232
SDValue FalseVal = GetPromotedFloat(N->getOperand(2));
32213233

3222-
return DAG.getNode(ISD::SELECT, SDLoc(N), TrueVal->getValueType(0),
3234+
return DAG.getNode(N->getOpcode(), SDLoc(N), TrueVal->getValueType(0),
32233235
N->getOperand(0), TrueVal, FalseVal);
32243236
}
32253237

@@ -3403,6 +3415,9 @@ void DAGTypeLegalizer::SoftPromoteHalfResult(SDNode *N, unsigned ResNo) {
34033415
R = SoftPromoteHalfRes_ATOMIC_LOAD(N);
34043416
break;
34053417
case ISD::SELECT: R = SoftPromoteHalfRes_SELECT(N); break;
3418+
case ISD::CTSELECT:
3419+
R = SoftPromoteHalfRes_SELECT(N);
3420+
break;
34063421
case ISD::SELECT_CC: R = SoftPromoteHalfRes_SELECT_CC(N); break;
34073422
case ISD::STRICT_SINT_TO_FP:
34083423
case ISD::STRICT_UINT_TO_FP:

0 commit comments

Comments
 (0)