Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
14 pmbaty 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