File indexing completed on 2026-05-10 08:44:00
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef LLVM_IR_FIXEDPOINTBUILDER_H
0015 #define LLVM_IR_FIXEDPOINTBUILDER_H
0016
0017 #include "llvm/ADT/APFixedPoint.h"
0018 #include "llvm/IR/Constant.h"
0019 #include "llvm/IR/Constants.h"
0020 #include "llvm/IR/IRBuilder.h"
0021 #include "llvm/IR/InstrTypes.h"
0022 #include "llvm/IR/Instruction.h"
0023 #include "llvm/IR/IntrinsicInst.h"
0024 #include "llvm/IR/Intrinsics.h"
0025 #include "llvm/IR/Type.h"
0026 #include "llvm/IR/Value.h"
0027
0028 #include <cmath>
0029
0030 namespace llvm {
0031
0032 template <class IRBuilderTy> class FixedPointBuilder {
0033 IRBuilderTy &B;
0034
0035 Value *Convert(Value *Src, const FixedPointSemantics &SrcSema,
0036 const FixedPointSemantics &DstSema, bool DstIsInteger) {
0037 unsigned SrcWidth = SrcSema.getWidth();
0038 unsigned DstWidth = DstSema.getWidth();
0039 unsigned SrcScale = SrcSema.getScale();
0040 unsigned DstScale = DstSema.getScale();
0041 bool SrcIsSigned = SrcSema.isSigned();
0042 bool DstIsSigned = DstSema.isSigned();
0043
0044 Type *DstIntTy = B.getIntNTy(DstWidth);
0045
0046 Value *Result = Src;
0047 unsigned ResultWidth = SrcWidth;
0048
0049
0050 if (DstScale < SrcScale) {
0051
0052
0053
0054 if (DstIsInteger && SrcIsSigned) {
0055 Value *Zero = Constant::getNullValue(Result->getType());
0056 Value *IsNegative = B.CreateICmpSLT(Result, Zero);
0057 Value *LowBits = ConstantInt::get(
0058 B.getContext(), APInt::getLowBitsSet(ResultWidth, SrcScale));
0059 Value *Rounded = B.CreateAdd(Result, LowBits);
0060 Result = B.CreateSelect(IsNegative, Rounded, Result);
0061 }
0062
0063 Result = SrcIsSigned
0064 ? B.CreateAShr(Result, SrcScale - DstScale, "downscale")
0065 : B.CreateLShr(Result, SrcScale - DstScale, "downscale");
0066 }
0067
0068 if (!DstSema.isSaturated()) {
0069
0070 Result = B.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
0071
0072
0073 if (DstScale > SrcScale)
0074 Result = B.CreateShl(Result, DstScale - SrcScale, "upscale");
0075 } else {
0076
0077 if (DstScale > SrcScale) {
0078
0079 ResultWidth = std::max(SrcWidth + DstScale - SrcScale, DstWidth);
0080 Type *UpscaledTy = B.getIntNTy(ResultWidth);
0081 Result = B.CreateIntCast(Result, UpscaledTy, SrcIsSigned, "resize");
0082 Result = B.CreateShl(Result, DstScale - SrcScale, "upscale");
0083 }
0084
0085
0086 bool LessIntBits = DstSema.getIntegralBits() < SrcSema.getIntegralBits();
0087 if (LessIntBits) {
0088 Value *Max = ConstantInt::get(
0089 B.getContext(),
0090 APFixedPoint::getMax(DstSema).getValue().extOrTrunc(ResultWidth));
0091 Value *TooHigh = SrcIsSigned ? B.CreateICmpSGT(Result, Max)
0092 : B.CreateICmpUGT(Result, Max);
0093 Result = B.CreateSelect(TooHigh, Max, Result, "satmax");
0094 }
0095
0096
0097 if (SrcIsSigned && (LessIntBits || !DstIsSigned)) {
0098 Value *Min = ConstantInt::get(
0099 B.getContext(),
0100 APFixedPoint::getMin(DstSema).getValue().extOrTrunc(ResultWidth));
0101 Value *TooLow = B.CreateICmpSLT(Result, Min);
0102 Result = B.CreateSelect(TooLow, Min, Result, "satmin");
0103 }
0104
0105
0106 if (ResultWidth != DstWidth)
0107 Result = B.CreateIntCast(Result, DstIntTy, SrcIsSigned, "resize");
0108 }
0109 return Result;
0110 }
0111
0112
0113
0114 FixedPointSemantics
0115 getCommonBinopSemantic(const FixedPointSemantics &LHSSema,
0116 const FixedPointSemantics &RHSSema) {
0117 auto C = LHSSema.getCommonSemantics(RHSSema);
0118 bool BothPadded =
0119 LHSSema.hasUnsignedPadding() && RHSSema.hasUnsignedPadding();
0120 return FixedPointSemantics(
0121 C.getWidth() + (unsigned)(BothPadded && C.isSaturated()), C.getScale(),
0122 C.isSigned(), C.isSaturated(), BothPadded);
0123 }
0124
0125
0126
0127
0128 Type *getAccommodatingFloatType(Type *Ty, const FixedPointSemantics &Sema) {
0129 const fltSemantics *FloatSema = &Ty->getFltSemantics();
0130 while (!Sema.fitsInFloatSemantics(*FloatSema))
0131 FloatSema = APFixedPoint::promoteFloatSemantics(FloatSema);
0132 return Type::getFloatingPointTy(Ty->getContext(), *FloatSema);
0133 }
0134
0135 public:
0136 FixedPointBuilder(IRBuilderTy &Builder) : B(Builder) {}
0137
0138
0139
0140
0141
0142
0143 Value *CreateFixedToFixed(Value *Src, const FixedPointSemantics &SrcSema,
0144 const FixedPointSemantics &DstSema) {
0145 return Convert(Src, SrcSema, DstSema, false);
0146 }
0147
0148
0149
0150
0151
0152
0153
0154 Value *CreateFixedToInteger(Value *Src, const FixedPointSemantics &SrcSema,
0155 unsigned DstWidth, bool DstIsSigned) {
0156 return Convert(
0157 Src, SrcSema,
0158 FixedPointSemantics::GetIntegerSemantics(DstWidth, DstIsSigned), true);
0159 }
0160
0161
0162
0163
0164
0165
0166 Value *CreateIntegerToFixed(Value *Src, unsigned SrcIsSigned,
0167 const FixedPointSemantics &DstSema) {
0168 return Convert(Src,
0169 FixedPointSemantics::GetIntegerSemantics(
0170 Src->getType()->getScalarSizeInBits(), SrcIsSigned),
0171 DstSema, false);
0172 }
0173
0174 Value *CreateFixedToFloating(Value *Src, const FixedPointSemantics &SrcSema,
0175 Type *DstTy) {
0176 Value *Result;
0177 Type *OpTy = getAccommodatingFloatType(DstTy, SrcSema);
0178
0179
0180 Result = SrcSema.isSigned() ? B.CreateSIToFP(Src, OpTy)
0181 : B.CreateUIToFP(Src, OpTy);
0182
0183
0184 Result = B.CreateFMul(Result,
0185 ConstantFP::get(OpTy, std::pow(2, -(int)SrcSema.getScale())));
0186 if (OpTy != DstTy)
0187 Result = B.CreateFPTrunc(Result, DstTy);
0188 return Result;
0189 }
0190
0191 Value *CreateFloatingToFixed(Value *Src, const FixedPointSemantics &DstSema) {
0192 bool UseSigned = DstSema.isSigned() || DstSema.hasUnsignedPadding();
0193 Value *Result = Src;
0194 Type *OpTy = getAccommodatingFloatType(Src->getType(), DstSema);
0195 if (OpTy != Src->getType())
0196 Result = B.CreateFPExt(Result, OpTy);
0197
0198
0199 Result = B.CreateFMul(Result,
0200 ConstantFP::get(OpTy, std::pow(2, DstSema.getScale())));
0201
0202 Type *ResultTy = B.getIntNTy(DstSema.getWidth());
0203 if (DstSema.isSaturated()) {
0204 Intrinsic::ID IID =
0205 UseSigned ? Intrinsic::fptosi_sat : Intrinsic::fptoui_sat;
0206 Result = B.CreateIntrinsic(IID, {ResultTy, OpTy}, {Result});
0207 } else {
0208 Result = UseSigned ? B.CreateFPToSI(Result, ResultTy)
0209 : B.CreateFPToUI(Result, ResultTy);
0210 }
0211
0212
0213
0214 if (DstSema.isSaturated() && DstSema.hasUnsignedPadding()) {
0215 Constant *Zero = Constant::getNullValue(Result->getType());
0216 Result =
0217 B.CreateSelect(B.CreateICmpSLT(Result, Zero), Zero, Result, "satmin");
0218 }
0219
0220 return Result;
0221 }
0222
0223
0224
0225
0226
0227
0228 Value *CreateAdd(Value *LHS, const FixedPointSemantics &LHSSema,
0229 Value *RHS, const FixedPointSemantics &RHSSema) {
0230 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0231 bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
0232
0233 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0234 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0235
0236 Value *Result;
0237 if (CommonSema.isSaturated()) {
0238 Intrinsic::ID IID = UseSigned ? Intrinsic::sadd_sat : Intrinsic::uadd_sat;
0239 Result = B.CreateBinaryIntrinsic(IID, WideLHS, WideRHS);
0240 } else {
0241 Result = B.CreateAdd(WideLHS, WideRHS);
0242 }
0243
0244 return CreateFixedToFixed(Result, CommonSema,
0245 LHSSema.getCommonSemantics(RHSSema));
0246 }
0247
0248
0249
0250
0251
0252
0253
0254 Value *CreateSub(Value *LHS, const FixedPointSemantics &LHSSema,
0255 Value *RHS, const FixedPointSemantics &RHSSema) {
0256 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0257 bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
0258
0259 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0260 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0261
0262 Value *Result;
0263 if (CommonSema.isSaturated()) {
0264 Intrinsic::ID IID = UseSigned ? Intrinsic::ssub_sat : Intrinsic::usub_sat;
0265 Result = B.CreateBinaryIntrinsic(IID, WideLHS, WideRHS);
0266 } else {
0267 Result = B.CreateSub(WideLHS, WideRHS);
0268 }
0269
0270
0271
0272 if (CommonSema.isSaturated() && CommonSema.hasUnsignedPadding()) {
0273 Constant *Zero = Constant::getNullValue(Result->getType());
0274 Result =
0275 B.CreateSelect(B.CreateICmpSLT(Result, Zero), Zero, Result, "satmin");
0276 }
0277
0278 return CreateFixedToFixed(Result, CommonSema,
0279 LHSSema.getCommonSemantics(RHSSema));
0280 }
0281
0282
0283
0284
0285
0286
0287
0288 Value *CreateMul(Value *LHS, const FixedPointSemantics &LHSSema,
0289 Value *RHS, const FixedPointSemantics &RHSSema) {
0290 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0291 bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
0292
0293 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0294 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0295
0296 Intrinsic::ID IID;
0297 if (CommonSema.isSaturated()) {
0298 IID = UseSigned ? Intrinsic::smul_fix_sat : Intrinsic::umul_fix_sat;
0299 } else {
0300 IID = UseSigned ? Intrinsic::smul_fix : Intrinsic::umul_fix;
0301 }
0302 Value *Result = B.CreateIntrinsic(
0303 IID, {WideLHS->getType()},
0304 {WideLHS, WideRHS, B.getInt32(CommonSema.getScale())});
0305
0306 return CreateFixedToFixed(Result, CommonSema,
0307 LHSSema.getCommonSemantics(RHSSema));
0308 }
0309
0310
0311
0312
0313
0314
0315
0316 Value *CreateDiv(Value *LHS, const FixedPointSemantics &LHSSema,
0317 Value *RHS, const FixedPointSemantics &RHSSema) {
0318 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0319 bool UseSigned = CommonSema.isSigned() || CommonSema.hasUnsignedPadding();
0320
0321 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0322 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0323
0324 Intrinsic::ID IID;
0325 if (CommonSema.isSaturated()) {
0326 IID = UseSigned ? Intrinsic::sdiv_fix_sat : Intrinsic::udiv_fix_sat;
0327 } else {
0328 IID = UseSigned ? Intrinsic::sdiv_fix : Intrinsic::udiv_fix;
0329 }
0330 Value *Result = B.CreateIntrinsic(
0331 IID, {WideLHS->getType()},
0332 {WideLHS, WideRHS, B.getInt32(CommonSema.getScale())});
0333
0334 return CreateFixedToFixed(Result, CommonSema,
0335 LHSSema.getCommonSemantics(RHSSema));
0336 }
0337
0338
0339
0340
0341
0342
0343 Value *CreateShl(Value *LHS, const FixedPointSemantics &LHSSema, Value *RHS) {
0344 bool UseSigned = LHSSema.isSigned() || LHSSema.hasUnsignedPadding();
0345
0346 RHS = B.CreateIntCast(RHS, LHS->getType(), false);
0347
0348 Value *Result;
0349 if (LHSSema.isSaturated()) {
0350 Intrinsic::ID IID = UseSigned ? Intrinsic::sshl_sat : Intrinsic::ushl_sat;
0351 Result = B.CreateBinaryIntrinsic(IID, LHS, RHS);
0352 } else {
0353 Result = B.CreateShl(LHS, RHS);
0354 }
0355
0356 return Result;
0357 }
0358
0359
0360
0361
0362
0363
0364 Value *CreateShr(Value *LHS, const FixedPointSemantics &LHSSema, Value *RHS) {
0365 RHS = B.CreateIntCast(RHS, LHS->getType(), false);
0366
0367 return LHSSema.isSigned() ? B.CreateAShr(LHS, RHS) : B.CreateLShr(LHS, RHS);
0368 }
0369
0370
0371
0372
0373
0374
0375 Value *CreateEQ(Value *LHS, const FixedPointSemantics &LHSSema,
0376 Value *RHS, const FixedPointSemantics &RHSSema) {
0377 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0378
0379 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0380 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0381
0382 return B.CreateICmpEQ(WideLHS, WideRHS);
0383 }
0384
0385
0386
0387
0388
0389
0390 Value *CreateNE(Value *LHS, const FixedPointSemantics &LHSSema,
0391 Value *RHS, const FixedPointSemantics &RHSSema) {
0392 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0393
0394 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0395 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0396
0397 return B.CreateICmpNE(WideLHS, WideRHS);
0398 }
0399
0400
0401
0402
0403
0404
0405 Value *CreateLT(Value *LHS, const FixedPointSemantics &LHSSema,
0406 Value *RHS, const FixedPointSemantics &RHSSema) {
0407 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0408
0409 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0410 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0411
0412 return CommonSema.isSigned() ? B.CreateICmpSLT(WideLHS, WideRHS)
0413 : B.CreateICmpULT(WideLHS, WideRHS);
0414 }
0415
0416
0417
0418
0419
0420
0421 Value *CreateLE(Value *LHS, const FixedPointSemantics &LHSSema,
0422 Value *RHS, const FixedPointSemantics &RHSSema) {
0423 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0424
0425 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0426 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0427
0428 return CommonSema.isSigned() ? B.CreateICmpSLE(WideLHS, WideRHS)
0429 : B.CreateICmpULE(WideLHS, WideRHS);
0430 }
0431
0432
0433
0434
0435
0436
0437 Value *CreateGT(Value *LHS, const FixedPointSemantics &LHSSema,
0438 Value *RHS, const FixedPointSemantics &RHSSema) {
0439 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0440
0441 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0442 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0443
0444 return CommonSema.isSigned() ? B.CreateICmpSGT(WideLHS, WideRHS)
0445 : B.CreateICmpUGT(WideLHS, WideRHS);
0446 }
0447
0448
0449
0450
0451
0452
0453 Value *CreateGE(Value *LHS, const FixedPointSemantics &LHSSema,
0454 Value *RHS, const FixedPointSemantics &RHSSema) {
0455 auto CommonSema = getCommonBinopSemantic(LHSSema, RHSSema);
0456
0457 Value *WideLHS = CreateFixedToFixed(LHS, LHSSema, CommonSema);
0458 Value *WideRHS = CreateFixedToFixed(RHS, RHSSema, CommonSema);
0459
0460 return CommonSema.isSigned() ? B.CreateICmpSGE(WideLHS, WideRHS)
0461 : B.CreateICmpUGE(WideLHS, WideRHS);
0462 }
0463 };
0464
0465 }
0466
0467 #endif