diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -32,6 +32,7 @@ #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/FixedPointBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/GlobalVariable.h" @@ -356,11 +357,6 @@ /// and an integer. Value *EmitFixedPointConversion(Value *Src, QualType SrcTy, QualType DstTy, SourceLocation Loc); - Value *EmitFixedPointConversion(Value *Src, - llvm::FixedPointSemantics &SrcFixedSema, - llvm::FixedPointSemantics &DstFixedSema, - SourceLocation Loc, - bool DstIsInteger = false); /// Emit a conversion from the specified complex type to the specified /// destination type, where the destination type is an LLVM scalar type. @@ -1447,91 +1443,17 @@ SourceLocation Loc) { auto SrcFPSema = CGF.getContext().getFixedPointSemantics(SrcTy); auto DstFPSema = CGF.getContext().getFixedPointSemantics(DstTy); - return EmitFixedPointConversion(Src, SrcFPSema, DstFPSema, Loc, - DstTy->isIntegerType()); -} - -Value *ScalarExprEmitter::EmitFixedPointConversion( - Value *Src, llvm::FixedPointSemantics &SrcFPSema, - llvm::FixedPointSemantics &DstFPSema, - SourceLocation Loc, bool DstIsInteger) { - using llvm::APFixedPoint; - using llvm::APInt; - using llvm::ConstantInt; - using llvm::Value; - - unsigned SrcWidth = SrcFPSema.getWidth(); - unsigned DstWidth = DstFPSema.getWidth(); - unsigned SrcScale = SrcFPSema.getScale(); - unsigned DstScale = DstFPSema.getScale(); - bool SrcIsSigned = SrcFPSema.isSigned(); - bool DstIsSigned = DstFPSema.isSigned(); - - llvm::Type *DstIntTy = Builder.getIntNTy(DstWidth); - - Value *Result = Src; - unsigned ResultWidth = SrcWidth; - - // Downscale. - if (DstScale < SrcScale) { - // When converting to integers, we round towards zero. For negative numbers, - // right shifting rounds towards negative infinity. In this case, we can - // just round up before shifting. - if (DstIsInteger && SrcIsSigned) { - Value *Zero = llvm::Constant::getNullValue(Result->getType()); - Value *IsNegative = Builder.CreateICmpSLT(Result, Zero); - Value *LowBits = ConstantInt::get( - CGF.getLLVMContext(), APInt::getLowBitsSet(ResultWidth, SrcScale)); - Value *Rounded = Builder.CreateAdd(Result, LowBits); - Result = Builder.CreateSelect(IsNegative, Rounded, Result); - } - - Result = SrcIsSigned - ? Builder.CreateAShr(Result, SrcScale - DstScale, "downscale") - : Builder.CreateLShr(Result, SrcScale - DstScale, "downscale"); - } - - if (!DstFPSema.isSaturated()) { - // 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"); - } - - // Handle saturation. - 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"); - } - // 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"); - } - - // Resize the integer part to get the final destination size. - if (ResultWidth != DstWidth) - Result = Builder.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize"); - } + llvm::FixedPointBuilder FPBuilder(Builder); + llvm::Value *Result; + if (DstTy->isIntegerType()) + Result = FPBuilder.CreateFixedToInteger(Src, SrcFPSema, + DstFPSema.getWidth(), + DstFPSema.isSigned()); + else if (SrcTy->isIntegerType()) + Result = FPBuilder.CreateIntegerToFixed(Src, SrcFPSema.isSigned(), + DstFPSema); + else + Result = FPBuilder.CreateFixedToFixed(Src, SrcFPSema, DstFPSema); return Result; } @@ -2668,12 +2590,9 @@ // Now, convert from our invented integer literal to the type of the unary // op. This will upscale and saturate if necessary. This value can become // undef in some cases. - auto SrcSema = - llvm::FixedPointSemantics::GetIntegerSemantics( - value->getType()->getScalarSizeInBits(), /*IsSigned=*/true); + llvm::FixedPointBuilder FPBuilder(Builder); auto DstSema = CGF.getContext().getFixedPointSemantics(Info.Ty); - Info.RHS = EmitFixedPointConversion(Info.RHS, SrcSema, DstSema, - E->getExprLoc()); + Info.RHS = FPBuilder.CreateIntegerToFixed(Info.RHS, true, DstSema); value = EmitFixedPointBinOp(Info); // Objective-C pointer types. @@ -3596,84 +3515,41 @@ auto ResultFixedSema = Ctx.getFixedPointSemantics(ResultTy); auto CommonFixedSema = LHSFixedSema.getCommonSemantics(RHSFixedSema); - // Convert the operands to the full precision type. - Value *FullLHS = EmitFixedPointConversion(LHS, LHSFixedSema, CommonFixedSema, - op.E->getExprLoc()); - Value *FullRHS = EmitFixedPointConversion(RHS, RHSFixedSema, CommonFixedSema, - op.E->getExprLoc()); - // Perform the actual operation. Value *Result; + llvm::FixedPointBuilder FPBuilder(Builder); switch (op.Opcode) { case BO_AddAssign: - case BO_Add: { - if (CommonFixedSema.isSaturated()) { - llvm::Intrinsic::ID IID = CommonFixedSema.isSigned() - ? llvm::Intrinsic::sadd_sat - : llvm::Intrinsic::uadd_sat; - Result = Builder.CreateBinaryIntrinsic(IID, FullLHS, FullRHS); - } else { - Result = Builder.CreateAdd(FullLHS, FullRHS); - } + case BO_Add: + Result = FPBuilder.CreateAdd(LHS, LHSFixedSema, RHS, RHSFixedSema); break; - } case BO_SubAssign: - case BO_Sub: { - if (CommonFixedSema.isSaturated()) { - llvm::Intrinsic::ID IID = CommonFixedSema.isSigned() - ? llvm::Intrinsic::ssub_sat - : llvm::Intrinsic::usub_sat; - Result = Builder.CreateBinaryIntrinsic(IID, FullLHS, FullRHS); - } else { - Result = Builder.CreateSub(FullLHS, FullRHS); - } + case BO_Sub: + Result = FPBuilder.CreateSub(LHS, LHSFixedSema, RHS, RHSFixedSema); break; - } case BO_MulAssign: - case BO_Mul: { - llvm::Intrinsic::ID IID; - if (CommonFixedSema.isSaturated()) - IID = CommonFixedSema.isSigned() ? llvm::Intrinsic::smul_fix_sat - : llvm::Intrinsic::umul_fix_sat; - else - IID = CommonFixedSema.isSigned() ? llvm::Intrinsic::smul_fix - : llvm::Intrinsic::umul_fix; - Result = Builder.CreateIntrinsic(IID, {FullLHS->getType()}, - {FullLHS, FullRHS, Builder.getInt32(CommonFixedSema.getScale())}); + case BO_Mul: + Result = FPBuilder.CreateMul(LHS, LHSFixedSema, RHS, RHSFixedSema); break; - } case BO_DivAssign: - case BO_Div: { - llvm::Intrinsic::ID IID; - if (CommonFixedSema.isSaturated()) - IID = CommonFixedSema.isSigned() ? llvm::Intrinsic::sdiv_fix_sat - : llvm::Intrinsic::udiv_fix_sat; - else - IID = CommonFixedSema.isSigned() ? llvm::Intrinsic::sdiv_fix - : llvm::Intrinsic::udiv_fix; - Result = Builder.CreateIntrinsic(IID, {FullLHS->getType()}, - {FullLHS, FullRHS, Builder.getInt32(CommonFixedSema.getScale())}); - break; - } + case BO_Div: + Result = FPBuilder.CreateDiv(LHS, LHSFixedSema, RHS, RHSFixedSema); + break; case BO_LT: - return CommonFixedSema.isSigned() ? Builder.CreateICmpSLT(FullLHS, FullRHS) - : Builder.CreateICmpULT(FullLHS, FullRHS); + return FPBuilder.CreateLT(LHS, LHSFixedSema, RHS, RHSFixedSema); case BO_GT: - return CommonFixedSema.isSigned() ? Builder.CreateICmpSGT(FullLHS, FullRHS) - : Builder.CreateICmpUGT(FullLHS, FullRHS); + return FPBuilder.CreateGT(LHS, LHSFixedSema, RHS, RHSFixedSema); case BO_LE: - return CommonFixedSema.isSigned() ? Builder.CreateICmpSLE(FullLHS, FullRHS) - : Builder.CreateICmpULE(FullLHS, FullRHS); + return FPBuilder.CreateLE(LHS, LHSFixedSema, RHS, RHSFixedSema); case BO_GE: - return CommonFixedSema.isSigned() ? Builder.CreateICmpSGE(FullLHS, FullRHS) - : Builder.CreateICmpUGE(FullLHS, FullRHS); + return FPBuilder.CreateGE(LHS, LHSFixedSema, RHS, RHSFixedSema); case BO_EQ: // For equality operations, we assume any padding bits on unsigned types are // zero'd out. They could be overwritten through non-saturating operations // that cause overflow, but this leads to undefined behavior. - return Builder.CreateICmpEQ(FullLHS, FullRHS); + return FPBuilder.CreateEQ(LHS, LHSFixedSema, RHS, RHSFixedSema); case BO_NE: - return Builder.CreateICmpNE(FullLHS, FullRHS); + return FPBuilder.CreateNE(LHS, LHSFixedSema, RHS, RHSFixedSema); case BO_Shl: case BO_Shr: case BO_Cmp: @@ -3698,8 +3574,7 @@ } // Convert to the result type. - return EmitFixedPointConversion(Result, CommonFixedSema, ResultFixedSema, - op.E->getExprLoc()); + return FPBuilder.CreateFixedToFixed(Result, CommonFixedSema, ResultFixedSema); } Value *ScalarExprEmitter::EmitSub(const BinOpInfo &op) { diff --git a/clang/test/Frontend/fixed_point_add.c b/clang/test/Frontend/fixed_point_add.c --- a/clang/test/Frontend/fixed_point_add.c +++ b/clang/test/Frontend/fixed_point_add.c @@ -444,11 +444,10 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i16 [[TMP1]] to i15 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i15 @llvm.uadd.sat.i15(i15 [[RESIZE]], i15 [[RESIZE1]]) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i15 [[TMP2]] to i16 -// UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @usa_sat, align 2 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.sadd.sat.i16(i16 [[TMP0]], i16 [[TMP1]]) +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP2]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 +// UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @usa_sat, align 2 // UNSIGNED-NEXT: ret void // void sat_usasusausas() { @@ -469,11 +468,11 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i32, i32* @ua, align 4 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[TMP0]] to i31 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i16 [[TMP1]] to i31 -// UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i31 [[RESIZE1]], 8 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i31 @llvm.uadd.sat.i31(i31 [[RESIZE]], i31 [[UPSCALE]]) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i31 [[TMP2]] to i32 +// UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i16 [[TMP1]] to i32 +// UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.sadd.sat.i32(i32 [[TMP0]], i32 [[UPSCALE]]) +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i32 [[TMP2]] to i31 +// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i31 [[RESIZE1]] to i32 // UNSIGNED-NEXT: store i32 [[RESIZE2]], i32* @ua_sat, align 4 // UNSIGNED-NEXT: ret void // @@ -533,11 +532,10 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @uf_sat, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @uf_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i16 [[TMP1]] to i15 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i15 @llvm.uadd.sat.i15(i15 [[RESIZE]], i15 [[RESIZE1]]) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i15 [[TMP2]] to i16 -// UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @uf_sat, align 2 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.sadd.sat.i16(i16 [[TMP0]], i16 [[TMP1]]) +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP2]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 +// UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @uf_sat, align 2 // UNSIGNED-NEXT: ret void // void sat_ufsufsufs() { diff --git a/clang/test/Frontend/fixed_point_div.c b/clang/test/Frontend/fixed_point_div.c --- a/clang/test/Frontend/fixed_point_div.c +++ b/clang/test/Frontend/fixed_point_div.c @@ -252,7 +252,7 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa, align 2 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.udiv.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7) +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.sdiv.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7) // UNSIGNED-NEXT: store i16 [[TMP2]], i16* @usa, align 2 // UNSIGNED-NEXT: ret void // @@ -276,7 +276,7 @@ // UNSIGNED-NEXT: [[TMP1:%.*]] = load i32, i32* @ua, align 4 // UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i16 [[TMP0]] to i32 // UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.udiv.fix.i32(i32 [[UPSCALE]], i32 [[TMP1]], i32 15) +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.sdiv.fix.i32(i32 [[UPSCALE]], i32 [[TMP1]], i32 15) // UNSIGNED-NEXT: store i32 [[TMP2]], i32* @ua, align 4 // UNSIGNED-NEXT: ret void // @@ -298,7 +298,7 @@ // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i8, i8* @usf, align 1 // UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i8 [[TMP1]] to i16 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.udiv.fix.i16(i16 [[TMP0]], i16 [[RESIZE]], i32 7) +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.sdiv.fix.i16(i16 [[TMP0]], i16 [[RESIZE]], i32 7) // UNSIGNED-NEXT: store i16 [[TMP2]], i16* @usa, align 2 // UNSIGNED-NEXT: ret void // @@ -326,7 +326,7 @@ // UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i16 [[TMP0]] to i24 // UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i24 [[RESIZE]], 8 // UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i16 [[TMP1]] to i24 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i24 @llvm.udiv.fix.i24(i24 [[UPSCALE]], i24 [[RESIZE1]], i32 15) +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i24 @llvm.sdiv.fix.i24(i24 [[UPSCALE]], i24 [[RESIZE1]], i32 15) // UNSIGNED-NEXT: [[DOWNSCALE:%.*]] = lshr i24 [[TMP2]], 8 // UNSIGNED-NEXT: [[RESIZE2:%.*]] = trunc i24 [[DOWNSCALE]] to i16 // UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @usa, align 2 @@ -544,11 +544,10 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i16 [[TMP1]] to i15 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i15 @llvm.udiv.fix.sat.i15(i15 [[RESIZE]], i15 [[RESIZE1]], i32 7) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i15 [[TMP2]] to i16 -// UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @usa_sat, align 2 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.sdiv.fix.sat.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7) +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP2]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 +// UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @usa_sat, align 2 // UNSIGNED-NEXT: ret void // void sat_usasusausas() { @@ -569,11 +568,11 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i32, i32* @ua, align 4 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[TMP0]] to i31 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i16 [[TMP1]] to i31 -// UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i31 [[RESIZE1]], 8 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i31 @llvm.udiv.fix.sat.i31(i31 [[RESIZE]], i31 [[UPSCALE]], i32 15) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i31 [[TMP2]] to i32 +// UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i16 [[TMP1]] to i32 +// UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.sdiv.fix.sat.i32(i32 [[TMP0]], i32 [[UPSCALE]], i32 15) +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i32 [[TMP2]] to i31 +// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i31 [[RESIZE1]] to i32 // UNSIGNED-NEXT: store i32 [[RESIZE2]], i32* @ua_sat, align 4 // UNSIGNED-NEXT: ret void // @@ -633,11 +632,10 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @uf_sat, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @uf_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i16 [[TMP1]] to i15 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i15 @llvm.udiv.fix.sat.i15(i15 [[RESIZE]], i15 [[RESIZE1]], i32 15) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i15 [[TMP2]] to i16 -// UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @uf_sat, align 2 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.sdiv.fix.sat.i16(i16 [[TMP0]], i16 [[TMP1]], i32 15) +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP2]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 +// UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @uf_sat, align 2 // UNSIGNED-NEXT: ret void // void sat_ufsufsufs() { diff --git a/clang/test/Frontend/fixed_point_mul.c b/clang/test/Frontend/fixed_point_mul.c --- a/clang/test/Frontend/fixed_point_mul.c +++ b/clang/test/Frontend/fixed_point_mul.c @@ -252,7 +252,7 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa, align 2 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.umul.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7) +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.smul.fix.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7) // UNSIGNED-NEXT: store i16 [[TMP2]], i16* @usa, align 2 // UNSIGNED-NEXT: ret void // @@ -276,7 +276,7 @@ // UNSIGNED-NEXT: [[TMP1:%.*]] = load i32, i32* @ua, align 4 // UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i16 [[TMP0]] to i32 // UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.umul.fix.i32(i32 [[UPSCALE]], i32 [[TMP1]], i32 15) +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.smul.fix.i32(i32 [[UPSCALE]], i32 [[TMP1]], i32 15) // UNSIGNED-NEXT: store i32 [[TMP2]], i32* @ua, align 4 // UNSIGNED-NEXT: ret void // @@ -298,7 +298,7 @@ // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i8, i8* @usf, align 1 // UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i8 [[TMP1]] to i16 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.umul.fix.i16(i16 [[TMP0]], i16 [[RESIZE]], i32 7) +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.smul.fix.i16(i16 [[TMP0]], i16 [[RESIZE]], i32 7) // UNSIGNED-NEXT: store i16 [[TMP2]], i16* @usa, align 2 // UNSIGNED-NEXT: ret void // @@ -326,7 +326,7 @@ // UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i16 [[TMP0]] to i24 // UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i24 [[RESIZE]], 8 // UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i16 [[TMP1]] to i24 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i24 @llvm.umul.fix.i24(i24 [[UPSCALE]], i24 [[RESIZE1]], i32 15) +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i24 @llvm.smul.fix.i24(i24 [[UPSCALE]], i24 [[RESIZE1]], i32 15) // UNSIGNED-NEXT: [[DOWNSCALE:%.*]] = lshr i24 [[TMP2]], 8 // UNSIGNED-NEXT: [[RESIZE2:%.*]] = trunc i24 [[DOWNSCALE]] to i16 // UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @usa, align 2 @@ -544,11 +544,10 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i16 [[TMP1]] to i15 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i15 @llvm.umul.fix.sat.i15(i15 [[RESIZE]], i15 [[RESIZE1]], i32 7) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i15 [[TMP2]] to i16 -// UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @usa_sat, align 2 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.smul.fix.sat.i16(i16 [[TMP0]], i16 [[TMP1]], i32 7) +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP2]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 +// UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @usa_sat, align 2 // UNSIGNED-NEXT: ret void // void sat_usasusausas() { @@ -569,11 +568,11 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i32, i32* @ua, align 4 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[TMP0]] to i31 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i16 [[TMP1]] to i31 -// UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i31 [[RESIZE1]], 8 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i31 @llvm.umul.fix.sat.i31(i31 [[RESIZE]], i31 [[UPSCALE]], i32 15) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i31 [[TMP2]] to i32 +// UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i16 [[TMP1]] to i32 +// UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.smul.fix.sat.i32(i32 [[TMP0]], i32 [[UPSCALE]], i32 15) +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i32 [[TMP2]] to i31 +// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i31 [[RESIZE1]] to i32 // UNSIGNED-NEXT: store i32 [[RESIZE2]], i32* @ua_sat, align 4 // UNSIGNED-NEXT: ret void // @@ -633,11 +632,10 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @uf_sat, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @uf_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i16 [[TMP1]] to i15 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i15 @llvm.umul.fix.sat.i15(i15 [[RESIZE]], i15 [[RESIZE1]], i32 15) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i15 [[TMP2]] to i16 -// UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @uf_sat, align 2 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.smul.fix.sat.i16(i16 [[TMP0]], i16 [[TMP1]], i32 15) +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP2]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 +// UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @uf_sat, align 2 // UNSIGNED-NEXT: ret void // void sat_ufsufsufs() { diff --git a/clang/test/Frontend/fixed_point_sub.c b/clang/test/Frontend/fixed_point_sub.c --- a/clang/test/Frontend/fixed_point_sub.c +++ b/clang/test/Frontend/fixed_point_sub.c @@ -444,11 +444,12 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @usa, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i16 [[TMP1]] to i15 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i15 @llvm.usub.sat.i15(i15 [[RESIZE]], i15 [[RESIZE1]]) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i15 [[TMP2]] to i16 -// UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @usa_sat, align 2 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.ssub.sat.i16(i16 [[TMP0]], i16 [[TMP1]]) +// UNSIGNED-NEXT: [[TMP3:%.*]] = icmp slt i16 [[TMP2]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP3]], i16 0, i16 [[TMP2]] +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[SATMIN]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 +// UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @usa_sat, align 2 // UNSIGNED-NEXT: ret void // void sat_usasusausas() { @@ -469,11 +470,13 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i32, i32* @ua, align 4 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @usa_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[TMP0]] to i31 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i16 [[TMP1]] to i31 -// UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i31 [[RESIZE1]], 8 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i31 @llvm.usub.sat.i31(i31 [[RESIZE]], i31 [[UPSCALE]]) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i31 [[TMP2]] to i32 +// UNSIGNED-NEXT: [[RESIZE:%.*]] = zext i16 [[TMP1]] to i32 +// UNSIGNED-NEXT: [[UPSCALE:%.*]] = shl i32 [[RESIZE]], 8 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i32 @llvm.ssub.sat.i32(i32 [[TMP0]], i32 [[UPSCALE]]) +// UNSIGNED-NEXT: [[TMP3:%.*]] = icmp slt i32 [[TMP2]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP3]], i32 0, i32 [[TMP2]] +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i32 [[SATMIN]] to i31 +// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i31 [[RESIZE1]] to i32 // UNSIGNED-NEXT: store i32 [[RESIZE2]], i32* @ua_sat, align 4 // UNSIGNED-NEXT: ret void // @@ -533,11 +536,12 @@ // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @uf_sat, align 2 // UNSIGNED-NEXT: [[TMP1:%.*]] = load i16, i16* @uf_sat, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = trunc i16 [[TMP1]] to i15 -// UNSIGNED-NEXT: [[TMP2:%.*]] = call i15 @llvm.usub.sat.i15(i15 [[RESIZE]], i15 [[RESIZE1]]) -// UNSIGNED-NEXT: [[RESIZE2:%.*]] = zext i15 [[TMP2]] to i16 -// UNSIGNED-NEXT: store i16 [[RESIZE2]], i16* @uf_sat, align 2 +// UNSIGNED-NEXT: [[TMP2:%.*]] = call i16 @llvm.ssub.sat.i16(i16 [[TMP0]], i16 [[TMP1]]) +// UNSIGNED-NEXT: [[TMP3:%.*]] = icmp slt i16 [[TMP2]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP3]], i16 0, i16 [[TMP2]] +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[SATMIN]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 +// UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @uf_sat, align 2 // UNSIGNED-NEXT: ret void // void sat_ufsufsufs() { diff --git a/clang/test/Frontend/fixed_point_unary.c b/clang/test/Frontend/fixed_point_unary.c --- a/clang/test/Frontend/fixed_point_unary.c +++ b/clang/test/Frontend/fixed_point_unary.c @@ -148,9 +148,9 @@ // UNSIGNED-LABEL: @inc_sua( // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i32, i32* @sua, align 4 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[TMP0]] to i31 -// UNSIGNED-NEXT: [[TMP1:%.*]] = call i31 @llvm.uadd.sat.i31(i31 [[RESIZE]], i31 32768) -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i31 [[TMP1]] to i32 +// UNSIGNED-NEXT: [[TMP1:%.*]] = call i32 @llvm.sadd.sat.i32(i32 [[TMP0]], i32 32768) +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[TMP1]] to i31 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i31 [[RESIZE]] to i32 // UNSIGNED-NEXT: store i32 [[RESIZE1]], i32* @sua, align 4 // UNSIGNED-NEXT: ret void // @@ -168,9 +168,9 @@ // UNSIGNED-LABEL: @inc_susa( // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @susa, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[TMP1:%.*]] = call i15 @llvm.uadd.sat.i15(i15 [[RESIZE]], i15 128) -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[TMP1]] to i16 +// UNSIGNED-NEXT: [[TMP1:%.*]] = call i16 @llvm.sadd.sat.i16(i16 [[TMP0]], i16 128) +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP1]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 // UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @susa, align 2 // UNSIGNED-NEXT: ret void // @@ -188,9 +188,9 @@ // UNSIGNED-LABEL: @inc_suf( // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @suf, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[TMP1:%.*]] = call i15 @llvm.uadd.sat.i15(i15 [[RESIZE]], i15 -1) -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[TMP1]] to i16 +// UNSIGNED-NEXT: [[TMP1:%.*]] = call i16 @llvm.sadd.sat.i16(i16 [[TMP0]], i16 32767) +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP1]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 // UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @suf, align 2 // UNSIGNED-NEXT: ret void // @@ -329,9 +329,11 @@ // UNSIGNED-LABEL: @dec_sua( // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i32, i32* @sua, align 4 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[TMP0]] to i31 -// UNSIGNED-NEXT: [[TMP1:%.*]] = call i31 @llvm.usub.sat.i31(i31 [[RESIZE]], i31 32768) -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i31 [[TMP1]] to i32 +// UNSIGNED-NEXT: [[TMP1:%.*]] = call i32 @llvm.ssub.sat.i32(i32 [[TMP0]], i32 32768) +// UNSIGNED-NEXT: [[TMP2:%.*]] = icmp slt i32 [[TMP1]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP2]], i32 0, i32 [[TMP1]] +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i32 [[SATMIN]] to i31 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i31 [[RESIZE]] to i32 // UNSIGNED-NEXT: store i32 [[RESIZE1]], i32* @sua, align 4 // UNSIGNED-NEXT: ret void // @@ -349,9 +351,11 @@ // UNSIGNED-LABEL: @dec_susa( // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @susa, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[TMP1:%.*]] = call i15 @llvm.usub.sat.i15(i15 [[RESIZE]], i15 128) -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[TMP1]] to i16 +// UNSIGNED-NEXT: [[TMP1:%.*]] = call i16 @llvm.ssub.sat.i16(i16 [[TMP0]], i16 128) +// UNSIGNED-NEXT: [[TMP2:%.*]] = icmp slt i16 [[TMP1]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP2]], i16 0, i16 [[TMP1]] +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[SATMIN]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 // UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @susa, align 2 // UNSIGNED-NEXT: ret void // @@ -369,9 +373,11 @@ // UNSIGNED-LABEL: @dec_suf( // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @suf, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[TMP1:%.*]] = call i15 @llvm.usub.sat.i15(i15 [[RESIZE]], i15 -1) -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[TMP1]] to i16 +// UNSIGNED-NEXT: [[TMP1:%.*]] = call i16 @llvm.ssub.sat.i16(i16 [[TMP0]], i16 32767) +// UNSIGNED-NEXT: [[TMP2:%.*]] = icmp slt i16 [[TMP1]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP2]], i16 0, i16 [[TMP1]] +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[SATMIN]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 // UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @suf, align 2 // UNSIGNED-NEXT: ret void // @@ -456,9 +462,11 @@ // UNSIGNED-LABEL: @neg_susa( // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @susa, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[TMP1:%.*]] = call i15 @llvm.usub.sat.i15(i15 0, i15 [[RESIZE]]) -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[TMP1]] to i16 +// UNSIGNED-NEXT: [[TMP1:%.*]] = call i16 @llvm.ssub.sat.i16(i16 0, i16 [[TMP0]]) +// UNSIGNED-NEXT: [[TMP2:%.*]] = icmp slt i16 [[TMP1]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP2]], i16 0, i16 [[TMP1]] +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[SATMIN]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 // UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @susa, align 2 // UNSIGNED-NEXT: ret void // @@ -476,9 +484,11 @@ // UNSIGNED-LABEL: @neg_suf( // UNSIGNED-NEXT: entry: // UNSIGNED-NEXT: [[TMP0:%.*]] = load i16, i16* @suf, align 2 -// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[TMP0]] to i15 -// UNSIGNED-NEXT: [[TMP1:%.*]] = call i15 @llvm.usub.sat.i15(i15 0, i15 [[RESIZE]]) -// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[TMP1]] to i16 +// UNSIGNED-NEXT: [[TMP1:%.*]] = call i16 @llvm.ssub.sat.i16(i16 0, i16 [[TMP0]]) +// UNSIGNED-NEXT: [[TMP2:%.*]] = icmp slt i16 [[TMP1]], 0 +// UNSIGNED-NEXT: [[SATMIN:%.*]] = select i1 [[TMP2]], i16 0, i16 [[TMP1]] +// UNSIGNED-NEXT: [[RESIZE:%.*]] = trunc i16 [[SATMIN]] to i15 +// UNSIGNED-NEXT: [[RESIZE1:%.*]] = zext i15 [[RESIZE]] to i16 // UNSIGNED-NEXT: store i16 [[RESIZE1]], i16* @suf, align 2 // UNSIGNED-NEXT: ret void //