Index: clang/lib/CodeGen/CGExprScalar.cpp =================================================================== --- clang/lib/CodeGen/CGExprScalar.cpp +++ clang/lib/CodeGen/CGExprScalar.cpp @@ -1452,7 +1452,6 @@ using llvm::ConstantInt; using llvm::Value; - unsigned SrcWidth = SrcFPSema.getWidth(); unsigned DstWidth = DstFPSema.getWidth(); unsigned SrcScale = SrcFPSema.getScale(); unsigned DstScale = DstFPSema.getScale(); @@ -1462,58 +1461,56 @@ llvm::Type *DstIntTy = Builder.getIntNTy(DstWidth); Value *Result = Src; - unsigned ResultWidth = SrcWidth; - if (!DstFPSema.isSaturated()) { - // Downscale. - if (DstScale < SrcScale) - Result = SrcIsSigned ? - Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") : - Builder.CreateLShr(Result, SrcScale - DstScale, "downscale"); + // Downscale. + if (DstScale < SrcScale) + Result = SrcIsSigned + ? Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") + : Builder.CreateLShr(Result, SrcScale - DstScale, "downscale"); - // Resize. - Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize"); + // Resize. + Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize"); - // Upscale. - if (DstScale > SrcScale) - Result = Builder.CreateShl(Result, DstScale - SrcScale, "upscale"); - } else { - // Adjust the number of fractional bits. - if (DstScale > SrcScale) { - // Compare to DstWidth to prevent resizing twice. - ResultWidth = std::max(SrcWidth + DstScale - SrcScale, DstWidth); - llvm::Type *UpscaledTy = Builder.getIntNTy(ResultWidth); - Result = Builder.CreateIntCast(Result, UpscaledTy, SrcIsSigned, "resize"); - Result = Builder.CreateShl(Result, DstScale - SrcScale, "upscale"); - } else if (DstScale < SrcScale) { - Result = SrcIsSigned ? - Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") : - Builder.CreateLShr(Result, SrcScale - DstScale, "downscale"); - } + // Upscale. + if (DstScale > SrcScale) + Result = Builder.CreateShl(Result, DstScale - SrcScale, "upscale"); + if (DstFPSema.isSaturated()) { // Handle saturation. + unsigned ResultWidth = Result->getType()->getIntegerBitWidth(); + bool LessIntBits = DstFPSema.getIntegralBits() < SrcFPSema.getIntegralBits(); if (LessIntBits) { - Value *Max = ConstantInt::get( - CGF.getLLVMContext(), - APFixedPoint::getMax(DstFPSema).getValue().extOrTrunc(ResultWidth)); - Value *TooHigh = SrcIsSigned ? Builder.CreateICmpSGT(Result, Max) - : Builder.CreateICmpUGT(Result, Max); - Result = Builder.CreateSelect(TooHigh, Max, Result, "satmax"); + APFixedPoint FXMax = APFixedPoint::getMax(DstFPSema); + + // This never overflows since the max is always positive and the semantics + // we convert to have more integral bits. + Value *MaxCmp = ConstantInt::get(CGF.getLLVMContext(), + FXMax.convert(SrcFPSema).getValue()); + + Value *Max = ConstantInt::get(CGF.getLLVMContext(), + FXMax.getValue().extOrTrunc(ResultWidth)); + Value *TooHigh = SrcIsSigned ? Builder.CreateICmpSGT(Src, MaxCmp) + : Builder.CreateICmpUGT(Src, MaxCmp); + Result = Builder.CreateSelect(TooHigh, Max, Result); } + // Cannot overflow min to dest type if src is unsigned since all fixed // point types can cover the unsigned min of 0. if (SrcIsSigned && (LessIntBits || !DstIsSigned)) { - Value *Min = ConstantInt::get( - CGF.getLLVMContext(), - APFixedPoint::getMin(DstFPSema).getValue().extOrTrunc(ResultWidth)); - Value *TooLow = Builder.CreateICmpSLT(Result, Min); - Result = Builder.CreateSelect(TooLow, Min, Result, "satmin"); + APFixedPoint FXMin = APFixedPoint::getMin(DstFPSema); + + // This never overflows since the min can always for in the range of + // values of the semantics we convert to. + Value *MinCmp = ConstantInt::get(CGF.getLLVMContext(), + FXMin.convert(SrcFPSema).getValue()); + + Value *Min = ConstantInt::get(CGF.getLLVMContext(), + FXMin.getValue().extOrTrunc(ResultWidth)); + Value *TooLow = SrcIsSigned ? Builder.CreateICmpSLT(Src, MinCmp) + : Builder.CreateICmpULT(Src, MinCmp); + Result = Builder.CreateSelect(TooLow, Min, Result); } - - // Resize the integer part to get the final destination size. - if (ResultWidth != DstWidth) - Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize"); } return Result; } Index: clang/test/Frontend/fixed_point_add.c =================================================================== --- clang/test/Frontend/fixed_point_add.c +++ clang/test/Frontend/fixed_point_add.c @@ -375,11 +375,11 @@ // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39 // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7 // CHECK-NEXT: [[SUM:%[0-9]+]] = call i39 @llvm.sadd.sat.i39(i39 [[SA_SAT_EXT]], i39 [[I]]) + // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16 // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[SUM]], 32767 - // CHECK-NEXT: [[RES:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[SUM]] - // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[RES]], -32768 - // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 -32768, i39 [[RES]] - // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = trunc i39 [[RES2]] to i16 + // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]] + // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SUM]], -32768 + // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RES2]] // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2 sa_sat = sa_sat + i; @@ -389,11 +389,11 @@ // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i40 // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i40 [[I_EXT]], 7 // CHECK-NEXT: [[SUM:%[0-9]+]] = call i40 @llvm.sadd.sat.i40(i40 [[SA_SAT_EXT]], i40 [[I]]) + // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16 // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[SUM]], 32767 - // CHECK-NEXT: [[RES:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 32767, i40 [[SUM]] - // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[RES]], -32768 - // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 -32768, i40 [[RES]] - // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = trunc i40 [[RES2]] to i16 + // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]] + // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SUM]], -32768 + // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RES2]] // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2 sa_sat = sa_sat + ui; @@ -414,20 +414,20 @@ // SIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i40 // SIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i40 [[I_RESIZE]], 8 // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i40 @llvm.uadd.sat.i40(i40 [[USA_SAT_RESIZE]], i40 [[I_UPSCALE]]) + // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16 // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[SUM]], 65535 - // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[SUM]] - // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[RESULT]], 0 - // SIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 0, i40 [[RESULT]] - // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i40 [[RESULT2]] to i16 + // SIGNED-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 -1, i16 [[RES]] + // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SUM]], 0 + // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RES2]] // UNSIGNED-NEXT: [[USA_SAT_RESIZE:%[a-z0-9]+]] = zext i16 [[USA_SAT]] to i39 // UNSIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i39 // UNSIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i39 [[I_RESIZE]], 7 // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i39 @llvm.uadd.sat.i39(i39 [[USA_SAT_RESIZE]], i39 [[I_UPSCALE]]) + // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16 // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[SUM]], 32767 - // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[SUM]] - // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[RESULT]], 0 - // UNSIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 0, i39 [[RESULT]] - // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i39 [[RESULT2]] to i16 + // UNSIGNED-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]] + // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SUM]], 0 + // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RES2]] // CHECK-NEXT: store i16 [[RESULT]], i16* %usa_sat, align 2 usa_sat = usa_sat + i; } Index: clang/test/Frontend/fixed_point_conversions.c =================================================================== --- clang/test/Frontend/fixed_point_conversions.c +++ clang/test/Frontend/fixed_point_conversions.c @@ -155,75 +155,76 @@ sat_sa = sat_a; // DEFAULT: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4 // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8 - // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767 - // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]] - // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768 - // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]] - // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16 - // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_sa, align 2 + // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16 + // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 8388352 + // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RESULT]] + // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], -8388608 + // DEFAULT-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RESULT2]] + // DEFAULT-NEXT: store i16 [[RESULT3]], i16* %sat_sa, align 2 // Accum to Fract, decreasing scale sat_sf = sat_a; // DEFAULT: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4 // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8 - // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[FRACT]], 127 - // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 127, i32 [[FRACT]] - // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -128 - // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -128, i32 [[RESULT]] - // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i8 - // DEFAULT-NEXT: store i8 [[RESULT_TRUNC]], i8* %sat_sf, align 1 + // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[FRACT]] to i8 + // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 32512 + // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i8 127, i8 [[RESULT]] + // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], -32768 + // DEFAULT-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i8 -128, i8 [[RESULT2]] + // DEFAULT-NEXT: store i8 [[RESULT3]], i8* %sat_sf, align 1 // Accum to Fract, same scale sat_f = a; // DEFAULT: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %a, align 4 + // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16 // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767 - // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]] - // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], -32768 - // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -32768, i32 [[RESULT]] - // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16 - // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_f, align 2 + // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RESULT]] + // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], -32768 + // DEFAULT-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RESULT2]] + // DEFAULT-NEXT: store i16 [[RESULT3]], i16* %sat_f, align 2 - // Accum to Fract, increasing scale + // Accum to Fract, increasing scale, same size sat_lf = sat_a; // DEFAULT: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4 - // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i48 - // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = shl i48 [[ACCUM]], 16 - // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i48 [[FRACT]], 2147483647 - // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i48 2147483647, i48 [[FRACT]] - // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i48 [[RESULT]], -2147483648 - // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i48 -2147483648, i48 [[RESULT]] - // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i48 [[RESULT2]] to i32 - // DEFAULT-NEXT: store i32 [[RESULT_TRUNC]], i32* %sat_lf, align 4 + // DEFAULT-NEXT: [[FRACT:%[0-9a-z]+]] = shl i32 [[OLD_ACCUM]], 16 + // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 32767 + // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 2147483647, i32 [[FRACT]] + // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], -32768 + // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 -2147483648, i32 [[RESULT]] + // DEFAULT-NEXT: store i32 [[RESULT2]], i32* %sat_lf, align 4 + + sat_a = sat_lf; + // DEFAULT: [[OLD_FRACT:%[0-9a-z]+]] = load i32, i32* %sat_lf, align 4 + // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_FRACT]], 16 + // DEFAULT-NEXT: store i32 [[ACCUM]], i32* %sat_a, align 4 // Signed to unsigned, decreasing scale _Sat _Accum sat_a2; sat_usa = sat_a2; // DEFAULT: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4 // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 7 - // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 65535 - // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 65535, i32 [[ACCUM]] - // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0 - // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]] - // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16 - // DEFAULT-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2 + // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16 + // DEFAULT-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 8388480 + // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i16 -1, i16 [[RESULT]] + // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], 0 + // DEFAULT-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RESULT2]] + // DEFAULT-NEXT: store i16 [[RESULT3]], i16* %sat_usa, align 2 // SAME: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a2, align 4 // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = ashr i32 [[OLD_ACCUM]], 8 - // SAME-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[ACCUM]], 32767 - // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MAX]], i32 32767, i32 [[ACCUM]] - // SAME-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[RESULT]], 0 - // SAME-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[RESULT]] - // SAME-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i32 [[RESULT2]] to i16 - // SAME-NEXT: store i16 [[RESULT_TRUNC]], i16* %sat_usa, align 2 - - // Signed to unsigned, increasing scale + // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = trunc i32 [[ACCUM]] to i16 + // SAME-NEXT: [[USE_MAX:%[0-9a-z]+]] = icmp sgt i32 [[OLD_ACCUM]], 8388352 + // SAME-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RESULT]] + // SAME-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], 0 + // SAME-NEXT: [[RESULT3:%[0-9a-z]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RESULT2]] + // SAME-NEXT: store i16 [[RESULT3]], i16* %sat_usa, align 2 + + // Signed to unsigned, increasing scale, same size sat_ua = sat_a; // DEFAULT: [[OLD_ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4 - // DEFAULT-NEXT: [[ACCUM_EXT:%[0-9a-z]+]] = sext i32 [[OLD_ACCUM]] to i33 - // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i33 [[ACCUM_EXT]], 1 - // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i33 [[ACCUM]], 0 - // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i33 0, i33 [[ACCUM]] - // DEFAULT-NEXT: [[RESULT_TRUNC:%[0-9a-z]+]] = trunc i33 [[RESULT2]] to i32 - // DEFAULT-NEXT: store i32 [[RESULT_TRUNC]], i32* %sat_ua, align 4 + // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[OLD_ACCUM]], 1 + // DEFAULT-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[OLD_ACCUM]], 0 + // DEFAULT-NEXT: [[RESULT2:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACCUM]] + // DEFAULT-NEXT: store i32 [[RESULT2]], i32* %sat_ua, align 4 // SAME: [[ACCUM:%[0-9a-z]+]] = load i32, i32* %sat_a, align 4 // SAME-NEXT: [[USE_MIN:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0 // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[USE_MIN]], i32 0, i32 [[ACCUM]] @@ -250,13 +251,13 @@ // DEFAULT: [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1 // DEFAULT-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32 // DEFAULT-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 9 - // DEFAULT-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0 + // DEFAULT-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i8 [[FRACT]], 0 // DEFAULT-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]] // DEFAULT-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4 // SAME: [[FRACT:%[0-9a-z]+]] = load i8, i8* %sat_sf, align 1 // SAME-NEXT: [[FRACT_EXT:%[0-9a-z]+]] = sext i8 [[FRACT]] to i32 // SAME-NEXT: [[ACCUM:%[0-9a-z]+]] = shl i32 [[FRACT_EXT]], 8 - // SAME-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i32 [[ACCUM]], 0 + // SAME-NEXT: [[IS_NEG:%[0-9a-z]+]] = icmp slt i8 [[FRACT]], 0 // SAME-NEXT: [[RESULT:%[0-9a-z]+]] = select i1 [[IS_NEG]], i32 0, i32 [[ACCUM]] // SAME-NEXT: store i32 [[RESULT]], i32* %sat_ua, align 4 } Index: clang/test/Frontend/fixed_point_sub.c =================================================================== --- clang/test/Frontend/fixed_point_sub.c +++ clang/test/Frontend/fixed_point_sub.c @@ -332,11 +332,11 @@ // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = sext i32 [[I]] to i39 // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i39 [[I_EXT]], 7 // CHECK-NEXT: [[SUM:%[0-9]+]] = call i39 @llvm.ssub.sat.i39(i39 [[SA_SAT_EXT]], i39 [[I]]) + // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16 // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[SUM]], 32767 - // CHECK-NEXT: [[RES:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[SUM]] - // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[RES]], -32768 - // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 -32768, i39 [[RES]] - // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = trunc i39 [[RES2]] to i16 + // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]] + // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SUM]], -32768 + // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RES2]] // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2 sa_sat = sa_sat - i; @@ -346,11 +346,11 @@ // CHECK-NEXT: [[I_EXT:%[a-z0-9]+]] = zext i32 [[I]] to i40 // CHECK-NEXT: [[I:%[a-z0-9]+]] = shl i40 [[I_EXT]], 7 // CHECK-NEXT: [[SUM:%[0-9]+]] = call i40 @llvm.ssub.sat.i40(i40 [[SA_SAT_EXT]], i40 [[I]]) + // CHECK-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16 // CHECK-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[SUM]], 32767 - // CHECK-NEXT: [[RES:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 32767, i40 [[SUM]] - // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[RES]], -32768 - // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 -32768, i40 [[RES]] - // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = trunc i40 [[RES2]] to i16 + // CHECK-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]] + // CHECK-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SUM]], -32768 + // CHECK-NEXT: [[RES3:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 -32768, i16 [[RES2]] // CHECK-NEXT: store i16 [[RES3]], i16* %sa_sat, align 2 sa_sat = sa_sat - ui; @@ -371,20 +371,20 @@ // SIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i40 // SIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i40 [[I_RESIZE]], 8 // SIGNED-NEXT: [[SUM:%[0-9]+]] = call i40 @llvm.usub.sat.i40(i40 [[USA_SAT_RESIZE]], i40 [[I_UPSCALE]]) + // SIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i40 [[SUM]] to i16 // SIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i40 [[SUM]], 65535 - // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i40 65535, i40 [[SUM]] - // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[RESULT]], 0 - // SIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i40 0, i40 [[RESULT]] - // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i40 [[RESULT2]] to i16 + // SIGNED-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 -1, i16 [[RES]] + // SIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i40 [[SUM]], 0 + // SIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RES2]] // UNSIGNED-NEXT: [[USA_SAT_RESIZE:%[a-z0-9]+]] = zext i16 [[USA_SAT]] to i39 // UNSIGNED-NEXT: [[I_RESIZE:%[a-z0-9]+]] = sext i32 [[I]] to i39 // UNSIGNED-NEXT: [[I_UPSCALE:%[a-z0-9]+]] = shl i39 [[I_RESIZE]], 7 // UNSIGNED-NEXT: [[SUM:%[0-9]+]] = call i39 @llvm.usub.sat.i39(i39 [[USA_SAT_RESIZE]], i39 [[I_UPSCALE]]) + // UNSIGNED-NEXT: [[RES:%[a-z0-9]+]] = trunc i39 [[SUM]] to i16 // UNSIGNED-NEXT: [[USE_MAX:%[0-9]+]] = icmp sgt i39 [[SUM]], 32767 - // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MAX]], i39 32767, i39 [[SUM]] - // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[RESULT]], 0 - // UNSIGNED-NEXT: [[RESULT2:%[a-z0-9]+]] = select i1 [[USE_MIN]], i39 0, i39 [[RESULT]] - // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = trunc i39 [[RESULT2]] to i16 + // UNSIGNED-NEXT: [[RES2:%[a-z0-9]+]] = select i1 [[USE_MAX]], i16 32767, i16 [[RES]] + // UNSIGNED-NEXT: [[USE_MIN:%[0-9]+]] = icmp slt i39 [[SUM]], 0 + // UNSIGNED-NEXT: [[RESULT:%[a-z0-9]+]] = select i1 [[USE_MIN]], i16 0, i16 [[RES2]] // CHECK-NEXT: store i16 [[RESULT]], i16* %usa_sat, align 2 usa_sat = usa_sat - i; }