Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. //===- llvm/FixedPointBuilder.h - Builder for fixed-point ops ---*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file defines the FixedPointBuilder class, which is used as a convenient
  10. // way to lower fixed-point arithmetic operations to LLVM IR.
  11. //
  12. //===----------------------------------------------------------------------===//
  13.  
  14. #ifndef LLVM_IR_FIXEDPOINTBUILDER_H
  15. #define LLVM_IR_FIXEDPOINTBUILDER_H
  16.  
  17. #include "llvm/ADT/APFixedPoint.h"
  18. #include "llvm/IR/Constant.h"
  19. #include "llvm/IR/Constants.h"
  20. #include "llvm/IR/IRBuilder.h"
  21. #include "llvm/IR/InstrTypes.h"
  22. #include "llvm/IR/Instruction.h"
  23. #include "llvm/IR/IntrinsicInst.h"
  24. #include "llvm/IR/Intrinsics.h"
  25. #include "llvm/IR/Type.h"
  26. #include "llvm/IR/Value.h"
  27.  
  28. #include <cmath>
  29.  
  30. namespace llvm {
  31.  
  32. template <class IRBuilderTy> class FixedPointBuilder {
  33.   IRBuilderTy &B;
  34.  
  35.   Value *Convert(Value *Src, const FixedPointSemantics &SrcSema,
  36.                  const FixedPointSemantics &DstSema, bool DstIsInteger) {
  37.     unsigned SrcWidth = SrcSema.getWidth();
  38.     unsigned DstWidth = DstSema.getWidth();
  39.     unsigned SrcScale = SrcSema.getScale();
  40.     unsigned DstScale = DstSema.getScale();
  41.     bool SrcIsSigned = SrcSema.isSigned();
  42.     bool DstIsSigned = DstSema.isSigned();
  43.  
  44.     Type *DstIntTy = B.getIntNTy(DstWidth);
  45.  
  46.     Value *Result = Src;
  47.     unsigned ResultWidth = SrcWidth;
  48.  
  49.     // Downscale.
  50.     if (DstScale < SrcScale) {
  51.       // When converting to integers, we round towards zero. For negative
  52.       // numbers, right shifting rounds towards negative infinity. In this case,
  53.       // we can just round up before shifting.
  54.       if (DstIsInteger && SrcIsSigned) {
  55.         Value *Zero = Constant::getNullValue(Result->getType());
  56.         Value *IsNegative = B.CreateICmpSLT(Result, Zero);
  57.         Value *LowBits = ConstantInt::get(
  58.             B.getContext(), APInt::getLowBitsSet(ResultWidth, SrcScale));
  59.         Value *Rounded = B.CreateAdd(Result, LowBits);
  60.         Result = B.CreateSelect(IsNegative, Rounded, Result);
  61.       }
  62.  
  63.       Result = SrcIsSigned
  64.                    ? B.CreateAShr(Result, SrcScale - DstScale, "downscale")
  65.                    : B.CreateLShr(Result, SrcScale - DstScale, "downscale");
  66.     }
  67.  
  68.     if (!DstSema.isSaturated()) {
  69.       // Resize.
  70.       Result = B.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
  71.  
  72.       // Upscale.
  73.       if (DstScale > SrcScale)
  74.         Result = B.CreateShl(Result, DstScale - SrcScale, "upscale");
  75.     } else {
  76.       // Adjust the number of fractional bits.
  77.       if (DstScale > SrcScale) {
  78.         // Compare to DstWidth to prevent resizing twice.
  79.         ResultWidth = std::max(SrcWidth + DstScale - SrcScale, DstWidth);
  80.         Type *UpscaledTy = B.getIntNTy(ResultWidth);
  81.         Result = B.CreateIntCast(Result, UpscaledTy, SrcIsSigned, "resize");
  82.         Result = B.CreateShl(Result, DstScale - SrcScale, "upscale");
  83.       }
  84.  
  85.       // Handle saturation.
  86.       bool LessIntBits = DstSema.getIntegralBits() < SrcSema.getIntegralBits();
  87.       if (LessIntBits) {
  88.         Value *Max = ConstantInt::get(
  89.             B.getContext(),
  90.             APFixedPoint::getMax(DstSema).getValue().extOrTrunc(ResultWidth));
  91.         Value *TooHigh = SrcIsSigned ? B.CreateICmpSGT(Result, Max)
  92.                                      : B.CreateICmpUGT(Result, Max);
  93.         Result = B.CreateSelect(TooHigh, Max, Result, "satmax");
  94.       }
  95.       // Cannot overflow min to dest type if src is unsigned since all fixed
  96.       // point types can cover the unsigned min of 0.
  97.       if (SrcIsSigned && (LessIntBits || !DstIsSigned)) {
  98.         Value *Min = ConstantInt::get(
  99.             B.getContext(),
  100.             APFixedPoint::getMin(DstSema).getValue().extOrTrunc(ResultWidth));
  101.         Value *TooLow = B.CreateICmpSLT(Result, Min);
  102.         Result = B.CreateSelect(TooLow, Min, Result, "satmin");
  103.       }
  104.  
  105.       // Resize the integer part to get the final destination size.
  106.       if (ResultWidth != DstWidth)
  107.         Result = B.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
  108.     }
  109.     return Result;
  110.   }
  111.  
  112.   /// Get the common semantic for two semantics, with the added imposition that
  113.   /// saturated padded types retain the padding bit.
  114.   FixedPointSemantics
  115.   getCommonBinopSemantic(const FixedPointSemantics &LHSSema,
  116.                          const FixedPointSemantics &RHSSema) {
  117.     auto C = LHSSema.getCommonSemantics(RHSSema);
  118.     bool BothPadded =
  119.         LHSSema.hasUnsignedPadding() && RHSSema.hasUnsignedPadding();
  120.     return FixedPointSemantics(
  121.         C.getWidth() + (unsigned)(BothPadded && C.isSaturated()), C.getScale(),
  122.         C.isSigned(), C.isSaturated(), BothPadded);
  123.   }
  124.  
  125.   /// Given a floating point type and a fixed-point semantic, return a floating
  126.   /// point type which can accommodate the fixed-point semantic. This is either
  127.   /// \p Ty, or a floating point type with a larger exponent than Ty.
  128.   Type *getAccommodatingFloatType(Type *Ty, const FixedPointSemantics &Sema) {
  129.     const fltSemantics *FloatSema = &Ty->getFltSemantics();
  130.     while (!Sema.fitsInFloatSemantics(*FloatSema))
  131.       FloatSema = APFixedPoint::promoteFloatSemantics(FloatSema);
  132.     return Type::getFloatingPointTy(Ty->getContext(), *FloatSema);
  133.   }
  134.  
  135. public:
  136.   FixedPointBuilder(IRBuilderTy &Builder) : B(Builder) {}
  137.  
  138.   /// Convert an integer value representing a fixed-point number from one
  139.   /// fixed-point semantic to another fixed-point semantic.
  140.   /// \p Src     - The source value
  141.   /// \p SrcSema - The fixed-point semantic of the source value
  142.   /// \p DstSema - The resulting fixed-point semantic
  143.   Value *CreateFixedToFixed(Value *Src, const FixedPointSemantics &SrcSema,
  144.                             const FixedPointSemantics &DstSema) {
  145.     return Convert(Src, SrcSema, DstSema, false);
  146.   }
  147.  
  148.   /// Convert an integer value representing a fixed-point number to an integer
  149.   /// with the given bit width and signedness.
  150.   /// \p Src         - The source value
  151.   /// \p SrcSema     - The fixed-point semantic of the source value
  152.   /// \p DstWidth    - The bit width of the result value
  153.   /// \p DstIsSigned - The signedness of the result value
  154.   Value *CreateFixedToInteger(Value *Src, const FixedPointSemantics &SrcSema,
  155.                               unsigned DstWidth, bool DstIsSigned) {
  156.     return Convert(
  157.         Src, SrcSema,
  158.         FixedPointSemantics::GetIntegerSemantics(DstWidth, DstIsSigned), true);
  159.   }
  160.  
  161.   /// Convert an integer value with the given signedness to an integer value
  162.   /// representing the given fixed-point semantic.
  163.   /// \p Src         - The source value
  164.   /// \p SrcIsSigned - The signedness of the source value
  165.   /// \p DstSema     - The resulting fixed-point semantic
  166.   Value *CreateIntegerToFixed(Value *Src, unsigned SrcIsSigned,
  167.                               const FixedPointSemantics &DstSema) {
  168.     return Convert(Src,
  169.                    FixedPointSemantics::GetIntegerSemantics(
  170.                        Src->getType()->getScalarSizeInBits(), SrcIsSigned),
  171.                    DstSema, false);
  172.   }
  173.  
  174.   Value *CreateFixedToFloating(Value *Src, const FixedPointSemantics &SrcSema,
  175.                                Type *DstTy) {
  176.     Value *Result;
  177.     Type *OpTy = getAccommodatingFloatType(DstTy, SrcSema);
  178.     // Convert the raw fixed-point value directly to floating point. If the
  179.     // value is too large to fit, it will be rounded, not truncated.
  180.     Result = SrcSema.isSigned() ? B.CreateSIToFP(Src, OpTy)
  181.                                 : B.CreateUIToFP(Src, OpTy);
  182.     // Rescale the integral-in-floating point by the scaling factor. This is
  183.     // lossless, except for overflow to infinity which is unlikely.
  184.     Result = B.CreateFMul(Result,
  185.         ConstantFP::get(OpTy, std::pow(2, -(int)SrcSema.getScale())));
  186.     if (OpTy != DstTy)
  187.       Result = B.CreateFPTrunc(Result, DstTy);
  188.     return Result;
  189.   }
  190.  
  191.   Value *CreateFloatingToFixed(Value *Src, const FixedPointSemantics &DstSema) {
  192.     bool UseSigned = DstSema.isSigned() || DstSema.hasUnsignedPadding();
  193.     Value *Result = Src;
  194.     Type *OpTy = getAccommodatingFloatType(Src->getType(), DstSema);
  195.     if (OpTy != Src->getType())
  196.       Result = B.CreateFPExt(Result, OpTy);
  197.     // Rescale the floating point value so that its significant bits (for the
  198.     // purposes of the conversion) are in the integral range.
  199.     Result = B.CreateFMul(Result,
  200.         ConstantFP::get(OpTy, std::pow(2, DstSema.getScale())));
  201.  
  202.     Type *ResultTy = B.getIntNTy(DstSema.getWidth());
  203.     if (DstSema.isSaturated()) {
  204.       Intrinsic::ID IID =
  205.           UseSigned ? Intrinsic::fptosi_sat : Intrinsic::fptoui_sat;
  206.       Result = B.CreateIntrinsic(IID, {ResultTy, OpTy}, {Result});
  207.     } else {
  208.       Result = UseSigned ? B.CreateFPToSI(Result, ResultTy)
  209.                          : B.CreateFPToUI(Result, ResultTy);
  210.     }
  211.  
  212.     // When saturating unsigned-with-padding using signed operations, we may
  213.     // get negative values. Emit an extra clamp to zero.
  214.     if (DstSema.isSaturated() && DstSema.hasUnsignedPadding()) {
  215.       Constant *Zero = Constant::getNullValue(Result->getType());
  216.       Result =
  217.           B.CreateSelect(B.CreateICmpSLT(Result, Zero), Zero, Result, "satmin");
  218.     }
  219.  
  220.     return Result;
  221.   }
  222.  
  223.   /// Add two fixed-point values and return the result in their common semantic.
  224.   /// \p LHS     - The left hand side
  225.   /// \p LHSSema - The semantic of the left hand side
  226.   /// \p RHS     - The right hand side
  227.   /// \p RHSSema - The semantic of the right hand side
  228.   Value *CreateAdd(Value *LHS, const FixedPointSemantics &LHSSema,
  229.                    Value *RHS, const FixedPointSemantics &RHSSema) {
  230.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  231.     bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
  232.  
  233.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  234.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  235.  
  236.     Value *Result;
  237.     if (CommonSema.isSaturated()) {
  238.       Intrinsic::ID IID = UseSigned ? Intrinsic::sadd_sat : Intrinsic::uadd_sat;
  239.       Result = B.CreateBinaryIntrinsic(IID, WideLHS, WideRHS);
  240.     } else {
  241.       Result = B.CreateAdd(WideLHS, WideRHS);
  242.     }
  243.  
  244.     return CreateFixedToFixed(Result, CommonSema,
  245.                               LHSSema.getCommonSemantics(RHSSema));
  246.   }
  247.  
  248.   /// Subtract two fixed-point values and return the result in their common
  249.   /// semantic.
  250.   /// \p LHS     - The left hand side
  251.   /// \p LHSSema - The semantic of the left hand side
  252.   /// \p RHS     - The right hand side
  253.   /// \p RHSSema - The semantic of the right hand side
  254.   Value *CreateSub(Value *LHS, const FixedPointSemantics &LHSSema,
  255.                    Value *RHS, const FixedPointSemantics &RHSSema) {
  256.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  257.     bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
  258.  
  259.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  260.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  261.  
  262.     Value *Result;
  263.     if (CommonSema.isSaturated()) {
  264.       Intrinsic::ID IID = UseSigned ? Intrinsic::ssub_sat : Intrinsic::usub_sat;
  265.       Result = B.CreateBinaryIntrinsic(IID, WideLHS, WideRHS);
  266.     } else {
  267.       Result = B.CreateSub(WideLHS, WideRHS);
  268.     }
  269.  
  270.     // Subtraction can end up below 0 for padded unsigned operations, so emit
  271.     // an extra clamp in that case.
  272.     if (CommonSema.isSaturated() && CommonSema.hasUnsignedPadding()) {
  273.       Constant *Zero = Constant::getNullValue(Result->getType());
  274.       Result =
  275.           B.CreateSelect(B.CreateICmpSLT(Result, Zero), Zero, Result, "satmin");
  276.     }
  277.  
  278.     return CreateFixedToFixed(Result, CommonSema,
  279.                               LHSSema.getCommonSemantics(RHSSema));
  280.   }
  281.  
  282.   /// Multiply two fixed-point values and return the result in their common
  283.   /// semantic.
  284.   /// \p LHS     - The left hand side
  285.   /// \p LHSSema - The semantic of the left hand side
  286.   /// \p RHS     - The right hand side
  287.   /// \p RHSSema - The semantic of the right hand side
  288.   Value *CreateMul(Value *LHS, const FixedPointSemantics &LHSSema,
  289.                    Value *RHS, const FixedPointSemantics &RHSSema) {
  290.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  291.     bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
  292.  
  293.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  294.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  295.  
  296.     Intrinsic::ID IID;
  297.     if (CommonSema.isSaturated()) {
  298.       IID = UseSigned ? Intrinsic::smul_fix_sat : Intrinsic::umul_fix_sat;
  299.     } else {
  300.       IID = UseSigned ? Intrinsic::smul_fix : Intrinsic::umul_fix;
  301.     }
  302.     Value *Result = B.CreateIntrinsic(
  303.         IID, {WideLHS->getType()},
  304.         {WideLHS, WideRHS, B.getInt32(CommonSema.getScale())});
  305.  
  306.     return CreateFixedToFixed(Result, CommonSema,
  307.                               LHSSema.getCommonSemantics(RHSSema));
  308.   }
  309.  
  310.   /// Divide two fixed-point values and return the result in their common
  311.   /// semantic.
  312.   /// \p LHS     - The left hand side
  313.   /// \p LHSSema - The semantic of the left hand side
  314.   /// \p RHS     - The right hand side
  315.   /// \p RHSSema - The semantic of the right hand side
  316.   Value *CreateDiv(Value *LHS, const FixedPointSemantics &LHSSema,
  317.                    Value *RHS, const FixedPointSemantics &RHSSema) {
  318.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  319.     bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
  320.  
  321.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  322.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  323.  
  324.     Intrinsic::ID IID;
  325.     if (CommonSema.isSaturated()) {
  326.       IID = UseSigned ? Intrinsic::sdiv_fix_sat : Intrinsic::udiv_fix_sat;
  327.     } else {
  328.       IID = UseSigned ? Intrinsic::sdiv_fix : Intrinsic::udiv_fix;
  329.     }
  330.     Value *Result = B.CreateIntrinsic(
  331.         IID, {WideLHS->getType()},
  332.         {WideLHS, WideRHS, B.getInt32(CommonSema.getScale())});
  333.  
  334.     return CreateFixedToFixed(Result, CommonSema,
  335.                               LHSSema.getCommonSemantics(RHSSema));
  336.   }
  337.  
  338.   /// Left shift a fixed-point value by an unsigned integer value. The integer
  339.   /// value can be any bit width.
  340.   /// \p LHS     - The left hand side
  341.   /// \p LHSSema - The semantic of the left hand side
  342.   /// \p RHS     - The right hand side
  343.   Value *CreateShl(Value *LHS, const FixedPointSemantics &LHSSema, Value *RHS) {
  344.     bool UseSigned = LHSSema.isSigned() || LHSSema.hasUnsignedPadding();
  345.  
  346.     RHS = B.CreateIntCast(RHS, LHS->getType(), /*IsSigned=*/false);
  347.  
  348.     Value *Result;
  349.     if (LHSSema.isSaturated()) {
  350.       Intrinsic::ID IID = UseSigned ? Intrinsic::sshl_sat : Intrinsic::ushl_sat;
  351.       Result = B.CreateBinaryIntrinsic(IID, LHS, RHS);
  352.     } else {
  353.       Result = B.CreateShl(LHS, RHS);
  354.     }
  355.  
  356.     return Result;
  357.   }
  358.  
  359.   /// Right shift a fixed-point value by an unsigned integer value. The integer
  360.   /// value can be any bit width.
  361.   /// \p LHS     - The left hand side
  362.   /// \p LHSSema - The semantic of the left hand side
  363.   /// \p RHS     - The right hand side
  364.   Value *CreateShr(Value *LHS, const FixedPointSemantics &LHSSema, Value *RHS) {
  365.     RHS = B.CreateIntCast(RHS, LHS->getType(), false);
  366.  
  367.     return LHSSema.isSigned() ? B.CreateAShr(LHS, RHS) : B.CreateLShr(LHS, RHS);
  368.   }
  369.  
  370.   /// Compare two fixed-point values for equality.
  371.   /// \p LHS     - The left hand side
  372.   /// \p LHSSema - The semantic of the left hand side
  373.   /// \p RHS     - The right hand side
  374.   /// \p RHSSema - The semantic of the right hand side
  375.   Value *CreateEQ(Value *LHS, const FixedPointSemantics &LHSSema,
  376.                   Value *RHS, const FixedPointSemantics &RHSSema) {
  377.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  378.  
  379.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  380.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  381.  
  382.     return B.CreateICmpEQ(WideLHS, WideRHS);
  383.   }
  384.  
  385.   /// Compare two fixed-point values for inequality.
  386.   /// \p LHS     - The left hand side
  387.   /// \p LHSSema - The semantic of the left hand side
  388.   /// \p RHS     - The right hand side
  389.   /// \p RHSSema - The semantic of the right hand side
  390.   Value *CreateNE(Value *LHS, const FixedPointSemantics &LHSSema,
  391.                   Value *RHS, const FixedPointSemantics &RHSSema) {
  392.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  393.  
  394.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  395.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  396.  
  397.     return B.CreateICmpNE(WideLHS, WideRHS);
  398.   }
  399.  
  400.   /// Compare two fixed-point values as LHS < RHS.
  401.   /// \p LHS     - The left hand side
  402.   /// \p LHSSema - The semantic of the left hand side
  403.   /// \p RHS     - The right hand side
  404.   /// \p RHSSema - The semantic of the right hand side
  405.   Value *CreateLT(Value *LHS, const FixedPointSemantics &LHSSema,
  406.                   Value *RHS, const FixedPointSemantics &RHSSema) {
  407.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  408.  
  409.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  410.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  411.  
  412.     return CommonSema.isSigned() ? B.CreateICmpSLT(WideLHS, WideRHS)
  413.                                  : B.CreateICmpULT(WideLHS, WideRHS);
  414.   }
  415.  
  416.   /// Compare two fixed-point values as LHS <= RHS.
  417.   /// \p LHS     - The left hand side
  418.   /// \p LHSSema - The semantic of the left hand side
  419.   /// \p RHS     - The right hand side
  420.   /// \p RHSSema - The semantic of the right hand side
  421.   Value *CreateLE(Value *LHS, const FixedPointSemantics &LHSSema,
  422.                   Value *RHS, const FixedPointSemantics &RHSSema) {
  423.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  424.  
  425.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  426.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  427.  
  428.     return CommonSema.isSigned() ? B.CreateICmpSLE(WideLHS, WideRHS)
  429.                                  : B.CreateICmpULE(WideLHS, WideRHS);
  430.   }
  431.  
  432.   /// Compare two fixed-point values as LHS > RHS.
  433.   /// \p LHS     - The left hand side
  434.   /// \p LHSSema - The semantic of the left hand side
  435.   /// \p RHS     - The right hand side
  436.   /// \p RHSSema - The semantic of the right hand side
  437.   Value *CreateGT(Value *LHS, const FixedPointSemantics &LHSSema,
  438.                   Value *RHS, const FixedPointSemantics &RHSSema) {
  439.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  440.  
  441.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  442.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  443.  
  444.     return CommonSema.isSigned() ? B.CreateICmpSGT(WideLHS, WideRHS)
  445.                                  : B.CreateICmpUGT(WideLHS, WideRHS);
  446.   }
  447.  
  448.   /// Compare two fixed-point values as LHS >= RHS.
  449.   /// \p LHS     - The left hand side
  450.   /// \p LHSSema - The semantic of the left hand side
  451.   /// \p RHS     - The right hand side
  452.   /// \p RHSSema - The semantic of the right hand side
  453.   Value *CreateGE(Value *LHS, const FixedPointSemantics &LHSSema,
  454.                   Value *RHS, const FixedPointSemantics &RHSSema) {
  455.     auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
  456.  
  457.     Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
  458.     Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
  459.  
  460.     return CommonSema.isSigned() ? B.CreateICmpSGE(WideLHS, WideRHS)
  461.                                  : B.CreateICmpUGE(WideLHS, WideRHS);
  462.   }
  463. };
  464.  
  465. } // end namespace llvm
  466.  
  467. #endif // LLVM_IR_FIXEDPOINTBUILDER_H
  468.