::
- <result> = select selty <cond>, <ty> <val1>, <ty> <val2> ; yields ty
+ <result> = select [fast-math flags] selty <cond>, <ty> <val1>, <ty> <val2> ; yields ty
selty is either i1 or {<N x i1>}
values indicating the condition, and two values of the same :ref:`first
class <t_firstclass>` type.
+#. The optional ``fast-math flags`` marker indicates that the select has one or more
+ :ref:`fast-math flags <fastmath>`. These are optimization hints to enable
+ otherwise unsafe floating-point optimizations. Fast-math flags are only valid
+ for selects that return a floating-point scalar or vector type.
+
Semantics:
""""""""""
MDNode *Unpred = MDFrom->getMetadata(LLVMContext::MD_unpredictable);
Sel = addBranchMetadata(Sel, Prof, Unpred);
}
+ if (isa<FPMathOperator>(Sel))
+ Sel = cast<SelectInst>(setFPAttrs(Sel, nullptr /* MDNode* */, FMF));
return Insert(Sel, Name);
}
case lltok::kw_inttoptr:
case lltok::kw_ptrtoint: return ParseCast(Inst, PFS, KeywordVal);
// Other.
- case lltok::kw_select: return ParseSelect(Inst, PFS);
+ case lltok::kw_select: {
+ FastMathFlags FMF = EatFastMathFlagsIfPresent();
+ int Res = ParseSelect(Inst, PFS);
+ if (Res != 0)
+ return Res;
+ if (FMF.any()) {
+ if (!Inst->getType()->isFPOrFPVectorTy())
+ return Error(Loc, "fast-math-flags specified for select without "
+ "floating-point scalar or vector return type");
+ Inst->setFastMathFlags(FMF);
+ }
+ return 0;
+ }
case lltok::kw_va_arg: return ParseVA_Arg(Inst, PFS);
case lltok::kw_extractelement: return ParseExtractElement(Inst, PFS);
case lltok::kw_insertelement: return ParseInsertElement(Inst, PFS);
I = SelectInst::Create(Cond, TrueVal, FalseVal);
InstructionList.push_back(I);
+ if (OpNum < Record.size() && isa<FPMathOperator>(I)) {
+ FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]);
+ if (FMF.any())
+ I->setFastMathFlags(FMF);
+ }
break;
}
Vals.append(IVI->idx_begin(), IVI->idx_end());
break;
}
- case Instruction::Select:
+ case Instruction::Select: {
Code = bitc::FUNC_CODE_INST_VSELECT;
pushValueAndType(I.getOperand(1), InstID, Vals);
pushValue(I.getOperand(2), InstID, Vals);
pushValueAndType(I.getOperand(0), InstID, Vals);
+ uint64_t Flags = getOptimizationFlags(&I);
+ if (Flags != 0)
+ Vals.push_back(Flags);
break;
+ }
case Instruction::ExtractElement:
Code = bitc::FUNC_CODE_INST_EXTRACTELT;
pushValueAndType(I.getOperand(0), InstID, Vals);
ret void
}
+define void @fastmathflags_select(i1 %cond, float %op1, float %op2) {
+ %f.nnan = select nnan i1 %cond, float %op1, float %op2
+ ; CHECK: %f.nnan = select nnan i1 %cond, float %op1, float %op2
+ %f.ninf = select ninf i1 %cond, float %op1, float %op2
+ ; CHECK: %f.ninf = select ninf i1 %cond, float %op1, float %op2
+ %f.nsz = select nsz i1 %cond, float %op1, float %op2
+ ; CHECK: %f.nsz = select nsz i1 %cond, float %op1, float %op2
+ %f.arcp = select arcp i1 %cond, float %op1, float %op2
+ ; CHECK: %f.arcp = select arcp i1 %cond, float %op1, float %op2
+ %f.contract = select contract i1 %cond, float %op1, float %op2
+ ; CHECK: %f.contract = select contract i1 %cond, float %op1, float %op2
+ %f.afn = select afn i1 %cond, float %op1, float %op2
+ ; CHECK: %f.afn = select afn i1 %cond, float %op1, float %op2
+ %f.reassoc = select reassoc i1 %cond, float %op1, float %op2
+ ; CHECK: %f.reassoc = select reassoc i1 %cond, float %op1, float %op2
+ %f.fast = select fast i1 %cond, float %op1, float %op2
+ ; CHECK: %f.fast = select fast i1 %cond, float %op1, float %op2
+ ret void
+}
+
+define void @fastmathflags_vector_select(<2 x i1> %cond, <2 x double> %op1, <2 x double> %op2) {
+ %f.nnan.nsz = select nnan nsz <2 x i1> %cond, <2 x double> %op1, <2 x double> %op2
+ ; CHECK: %f.nnan.nsz = select nnan nsz <2 x i1> %cond, <2 x double> %op1, <2 x double> %op2
+ %f.fast = select fast <2 x i1> %cond, <2 x double> %op1, <2 x double> %op2
+ ; CHECK: %f.fast = select fast <2 x i1> %cond, <2 x double> %op1, <2 x double> %op2
+ ret void
+}
+
; Check various fast math flags and floating-point types on calls.
declare float @fmf1()
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RDX_SHUF:%.*]] = shufflevector <2 x double> [[VEC:%.*]], <2 x double> undef, <2 x i32> <i32 1, i32 undef>
; CHECK-NEXT: [[RDX_MINMAX_CMP:%.*]] = fcmp fast ogt <2 x double> [[VEC]], [[RDX_SHUF]]
-; CHECK-NEXT: [[RDX_MINMAX_SELECT:%.*]] = select <2 x i1> [[RDX_MINMAX_CMP]], <2 x double> [[VEC]], <2 x double> [[RDX_SHUF]]
+; CHECK-NEXT: [[RDX_MINMAX_SELECT:%.*]] = select fast <2 x i1> [[RDX_MINMAX_CMP]], <2 x double> [[VEC]], <2 x double> [[RDX_SHUF]]
; CHECK-NEXT: [[TMP0:%.*]] = extractelement <2 x double> [[RDX_MINMAX_SELECT]], i32 0
; CHECK-NEXT: ret double [[TMP0]]
;
; CHECK-NEXT: entry:
; CHECK-NEXT: [[RDX_SHUF:%.*]] = shufflevector <2 x double> [[VEC:%.*]], <2 x double> undef, <2 x i32> <i32 1, i32 undef>
; CHECK-NEXT: [[RDX_MINMAX_CMP:%.*]] = fcmp fast olt <2 x double> [[VEC]], [[RDX_SHUF]]
-; CHECK-NEXT: [[RDX_MINMAX_SELECT:%.*]] = select <2 x i1> [[RDX_MINMAX_CMP]], <2 x double> [[VEC]], <2 x double> [[RDX_SHUF]]
+; CHECK-NEXT: [[RDX_MINMAX_SELECT:%.*]] = select fast <2 x i1> [[RDX_MINMAX_CMP]], <2 x double> [[VEC]], <2 x double> [[RDX_SHUF]]
; CHECK-NEXT: [[TMP0:%.*]] = extractelement <2 x double> [[RDX_MINMAX_SELECT]], i32 0
; CHECK-NEXT: ret double [[TMP0]]
;
define float @max1(float %a, float %b) {
; CHECK-LABEL: @max1(
; CHECK-NEXT: [[TMP1:%.*]] = fcmp fast ogt float [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = select fast i1 [[TMP1]], float [[A]], float [[B]]
; CHECK-NEXT: ret float [[TMP2]]
;
%c = fpext float %a to double
define float @max2(float %a, float %b) {
; CHECK-LABEL: @max2(
; CHECK-NEXT: [[TMP1:%.*]] = fcmp nnan nsz ogt float [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = select nnan nsz i1 [[TMP1]], float [[A]], float [[B]]
; CHECK-NEXT: ret float [[TMP2]]
;
%c = call nnan float @fmaxf(float %a, float %b)
define double @max3(double %a, double %b) {
; CHECK-LABEL: @max3(
; CHECK-NEXT: [[TMP1:%.*]] = fcmp fast ogt double [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], double [[A]], double [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = select fast i1 [[TMP1]], double [[A]], double [[B]]
; CHECK-NEXT: ret double [[TMP2]]
;
%c = call fast double @fmax(double %a, double %b)
define fp128 @max4(fp128 %a, fp128 %b) {
; CHECK-LABEL: @max4(
; CHECK-NEXT: [[TMP1:%.*]] = fcmp nnan nsz ogt fp128 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], fp128 [[A]], fp128 [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = select nnan nsz i1 [[TMP1]], fp128 [[A]], fp128 [[B]]
; CHECK-NEXT: ret fp128 [[TMP2]]
;
%c = call nnan fp128 @fmaxl(fp128 %a, fp128 %b)
define float @min1(float %a, float %b) {
; CHECK-LABEL: @min1(
; CHECK-NEXT: [[TMP1:%.*]] = fcmp nnan nsz olt float [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = select nnan nsz i1 [[TMP1]], float [[A]], float [[B]]
; CHECK-NEXT: ret float [[TMP2]]
;
%c = fpext float %a to double
define float @min2(float %a, float %b) {
; CHECK-LABEL: @min2(
; CHECK-NEXT: [[TMP1:%.*]] = fcmp fast olt float [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], float [[A]], float [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = select fast i1 [[TMP1]], float [[A]], float [[B]]
; CHECK-NEXT: ret float [[TMP2]]
;
%c = call fast float @fminf(float %a, float %b)
define double @min3(double %a, double %b) {
; CHECK-LABEL: @min3(
; CHECK-NEXT: [[TMP1:%.*]] = fcmp nnan nsz olt double [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], double [[A]], double [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = select nnan nsz i1 [[TMP1]], double [[A]], double [[B]]
; CHECK-NEXT: ret double [[TMP2]]
;
%c = call nnan double @fmin(double %a, double %b)
define fp128 @min4(fp128 %a, fp128 %b) {
; CHECK-LABEL: @min4(
; CHECK-NEXT: [[TMP1:%.*]] = fcmp fast olt fp128 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[TMP2:%.*]] = select i1 [[TMP1]], fp128 [[A]], fp128 [[B]]
+; CHECK-NEXT: [[TMP2:%.*]] = select fast i1 [[TMP1]], fp128 [[A]], fp128 [[B]]
; CHECK-NEXT: ret fp128 [[TMP2]]
;
%c = call fast fp128 @fminl(fp128 %a, fp128 %b)
; CHECK-NEXT: [[SQRT:%.*]] = call afn double @sqrt(double [[X:%.*]])
; CHECK-NEXT: [[ABS:%.*]] = call afn double @llvm.fabs.f64(double [[SQRT]])
; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq double [[X]], 0xFFF0000000000000
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]]
+; CHECK-NEXT: [[TMP1:%.*]] = select afn i1 [[ISINF]], double 0x7FF0000000000000, double [[ABS]]
; CHECK-NEXT: ret double [[TMP1]]
;
%pow = call afn double @pow(double %x, double 5.0e-01)
; CHECK-NEXT: [[SQRT:%.*]] = call afn <2 x double> @llvm.sqrt.v2f64(<2 x double> [[X:%.*]])
; CHECK-NEXT: [[ABS:%.*]] = call afn <2 x double> @llvm.fabs.v2f64(<2 x double> [[SQRT]])
; CHECK-NEXT: [[ISINF:%.*]] = fcmp afn oeq <2 x double> [[X]], <double 0xFFF0000000000000, double 0xFFF0000000000000>
-; CHECK-NEXT: [[TMP1:%.*]] = select <2 x i1> [[ISINF]], <2 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000>, <2 x double> [[ABS]]
+; CHECK-NEXT: [[TMP1:%.*]] = select afn <2 x i1> [[ISINF]], <2 x double> <double 0x7FF0000000000000, double 0x7FF0000000000000>, <2 x double> [[ABS]]
; CHECK-NEXT: ret <2 x double> [[TMP1]]
;
%pow = call afn <2 x double> @llvm.pow.v2f64(<2 x double> %x, <2 x double> <double 5.0e-01, double 5.0e-01>)
; CHECK-LABEL: @pow_libcall_half_nsz(
; CHECK-NEXT: [[SQRT:%.*]] = call nsz double @sqrt(double [[X:%.*]])
; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]]
+; CHECK-NEXT: [[TMP1:%.*]] = select nsz i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]]
; CHECK-NEXT: ret double [[TMP1]]
;
%pow = call nsz double @pow(double %x, double 5.0e-01)
; CHECK-LABEL: @pow_intrinsic_half_nsz(
; CHECK-NEXT: [[SQRT:%.*]] = call nsz double @llvm.sqrt.f64(double [[X:%.*]])
; CHECK-NEXT: [[ISINF:%.*]] = fcmp nsz oeq double [[X]], 0xFFF0000000000000
-; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]]
+; CHECK-NEXT: [[TMP1:%.*]] = select nsz i1 [[ISINF]], double 0x7FF0000000000000, double [[SQRT]]
; CHECK-NEXT: ret double [[TMP1]]
;
%pow = call nsz double @llvm.pow.f64(double %x, double 5.0e-01)
; CHECK: middle.block:
; CHECK-NEXT: [[RDX_SHUF:%.*]] = shufflevector <4 x float> [[TMP6]], <4 x float> undef, <4 x i32> <i32 2, i32 3, i32 undef, i32 undef>
; CHECK-NEXT: [[RDX_MINMAX_CMP:%.*]] = fcmp fast olt <4 x float> [[TMP6]], [[RDX_SHUF]]
-; CHECK-NEXT: [[RDX_MINMAX_SELECT:%.*]] = select <4 x i1> [[RDX_MINMAX_CMP]], <4 x float> [[TMP6]], <4 x float> [[RDX_SHUF]]
+; CHECK-NEXT: [[RDX_MINMAX_SELECT:%.*]] = select fast <4 x i1> [[RDX_MINMAX_CMP]], <4 x float> [[TMP6]], <4 x float> [[RDX_SHUF]]
; CHECK-NEXT: [[RDX_SHUF1:%.*]] = shufflevector <4 x float> [[RDX_MINMAX_SELECT]], <4 x float> undef, <4 x i32> <i32 1, i32 undef, i32 undef, i32 undef>
; CHECK-NEXT: [[RDX_MINMAX_CMP2:%.*]] = fcmp fast olt <4 x float> [[RDX_MINMAX_SELECT]], [[RDX_SHUF1]]
-; CHECK-NEXT: [[RDX_MINMAX_SELECT3:%.*]] = select <4 x i1> [[RDX_MINMAX_CMP2]], <4 x float> [[RDX_MINMAX_SELECT]], <4 x float> [[RDX_SHUF1]]
+; CHECK-NEXT: [[RDX_MINMAX_SELECT3:%.*]] = select fast <4 x i1> [[RDX_MINMAX_CMP2]], <4 x float> [[RDX_MINMAX_SELECT]], <4 x float> [[RDX_SHUF1]]
; CHECK-NEXT: [[TMP8:%.*]] = extractelement <4 x float> [[RDX_MINMAX_SELECT3]], i32 0
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 65536, 65536
; CHECK-NEXT: br i1 [[CMP_N]], label [[OUT:%.*]], label [[SCALAR_PH]]
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast ogt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @max_red_float(float %max) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast ogt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @max_red_float_ge(float %max) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast ogt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @inverted_max_red_float(float %max) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast ogt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @inverted_max_red_float_le(float %max) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast ogt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @unordered_max_red_float(float %max) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast ogt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @unordered_max_red_float_ge(float %max) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast ogt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @inverted_unordered_max_red_float(float %max) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast ogt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @inverted_unordered_max_red_float_le(float %max) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast olt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @min_red_float(float %min) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast olt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @min_red_float_le(float %min) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast olt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @inverted_min_red_float(float %min) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast olt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @inverted_min_red_float_ge(float %min) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast olt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @unordered_min_red_float(float %min) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast olt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @unordered_min_red_float_le(float %min) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast olt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @inverted_unordered_min_red_float(float %min) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast olt <2 x float>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define float @inverted_unordered_min_red_float_ge(float %min) #0 {
entry:
; CHECK: select <2 x i1>
; CHECK: middle.block
; CHECK: fcmp fast olt <2 x double>
-; CHECK: select <2 x i1>
+; CHECK: select fast <2 x i1>
define double @min_red_double(double %min) #0 {
entry: