@@ -125,6 +125,13 @@ struct BinOpInfo {
125
125
return CFP->isZero ();
126
126
return true ;
127
127
}
128
+
129
+ // / Check if either operand is a fixed point type, in which case, this
130
+ // / operation did not follow usual arithmetic conversion and both operands may
131
+ // / not be the same.
132
+ bool isFixedPointBinOp () const {
133
+ return isa<BinaryOperator>(E) && Ty->isFixedPointType ();
134
+ }
128
135
};
129
136
130
137
static bool MustVisitNullValue (const Expr *E) {
@@ -351,6 +358,9 @@ class ScalarExprEmitter
351
358
352
359
Value *EmitFixedPointConversion (Value *Src, QualType SrcTy, QualType DstTy,
353
360
SourceLocation Loc);
361
+ Value *EmitFixedPointConversion (Value *Src, FixedPointSemantics &SrcFixedSema,
362
+ FixedPointSemantics &DstFixedSema,
363
+ SourceLocation Loc);
354
364
355
365
// / Emit a conversion from the specified complex type to the specified
356
366
// / destination type, where the destination type is an LLVM scalar type.
@@ -729,6 +739,9 @@ class ScalarExprEmitter
729
739
return Builder.CreateOr (Ops.LHS , Ops.RHS , " or" );
730
740
}
731
741
742
+ // Helper functions for fixed point binary operations.
743
+ Value *EmitFixedPointAdd (const BinOpInfo &Ops);
744
+
732
745
BinOpInfo EmitBinOps (const BinaryOperator *E);
733
746
LValue EmitCompoundAssignLValue (const CompoundAssignOperator *E,
734
747
Value *(ScalarExprEmitter::*F)(const BinOpInfo &),
@@ -1423,17 +1436,23 @@ Value *ScalarExprEmitter::EmitScalarConversion(Value *Src, QualType SrcType,
1423
1436
Value *ScalarExprEmitter::EmitFixedPointConversion (Value *Src, QualType SrcTy,
1424
1437
QualType DstTy,
1425
1438
SourceLocation Loc) {
1426
- using llvm::APInt;
1427
- using llvm::ConstantInt;
1428
- using llvm::Value;
1429
-
1430
1439
assert (SrcTy->isFixedPointType ());
1431
1440
assert (DstTy->isFixedPointType ());
1432
1441
1433
1442
FixedPointSemantics SrcFPSema =
1434
1443
CGF.getContext ().getFixedPointSemantics (SrcTy);
1435
1444
FixedPointSemantics DstFPSema =
1436
1445
CGF.getContext ().getFixedPointSemantics (DstTy);
1446
+ return EmitFixedPointConversion (Src, SrcFPSema, DstFPSema, Loc);
1447
+ }
1448
+
1449
+ Value *ScalarExprEmitter::EmitFixedPointConversion (
1450
+ Value *Src, FixedPointSemantics &SrcFPSema, FixedPointSemantics &DstFPSema,
1451
+ SourceLocation Loc) {
1452
+ using llvm::APInt;
1453
+ using llvm::ConstantInt;
1454
+ using llvm::Value;
1455
+
1437
1456
unsigned SrcWidth = SrcFPSema.getWidth ();
1438
1457
unsigned DstWidth = DstFPSema.getWidth ();
1439
1458
unsigned SrcScale = SrcFPSema.getScale ();
@@ -1462,7 +1481,8 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
1462
1481
} else {
1463
1482
// Adjust the number of fractional bits.
1464
1483
if (DstScale > SrcScale) {
1465
- ResultWidth = SrcWidth + DstScale - SrcScale;
1484
+ // Compare to DstWidth to prevent resizing twice.
1485
+ ResultWidth = std::max (SrcWidth + DstScale - SrcScale, DstWidth);
1466
1486
llvm::Type *UpscaledTy = Builder.getIntNTy (ResultWidth);
1467
1487
Result = Builder.CreateIntCast (Result, UpscaledTy, SrcIsSigned, " resize" );
1468
1488
Result = Builder.CreateShl (Result, DstScale - SrcScale, " upscale" );
@@ -1493,7 +1513,8 @@ Value *ScalarExprEmitter::EmitFixedPointConversion(Value *Src, QualType SrcTy,
1493
1513
}
1494
1514
1495
1515
// Resize the integer part to get the final destination size.
1496
- Result = Builder.CreateIntCast (Result, DstIntTy, SrcIsSigned, " resize" );
1516
+ if (ResultWidth != DstWidth)
1517
+ Result = Builder.CreateIntCast (Result, DstIntTy, SrcIsSigned, " resize" );
1497
1518
}
1498
1519
return Result;
1499
1520
}
@@ -3338,9 +3359,58 @@ Value *ScalarExprEmitter::EmitAdd(const BinOpInfo &op) {
3338
3359
return propagateFMFlags (V, op);
3339
3360
}
3340
3361
3362
+ if (op.isFixedPointBinOp ())
3363
+ return EmitFixedPointAdd (op);
3364
+
3341
3365
return Builder.CreateAdd (op.LHS , op.RHS , " add" );
3342
3366
}
3343
3367
3368
+ // / The resulting value must be calculated with exact precision, so the operands
3369
+ // / may not be the same type.
3370
+ Value *ScalarExprEmitter::EmitFixedPointAdd (const BinOpInfo &op) {
3371
+ using llvm::APSInt;
3372
+ using llvm::ConstantInt;
3373
+
3374
+ const auto *BinOp = cast<BinaryOperator>(op.E );
3375
+ assert (BinOp->getOpcode () == BO_Add && " Expected operation to be addition" );
3376
+
3377
+ // The result is a fixed point type and at least one of the operands is fixed
3378
+ // point while the other is either fixed point or an int. This resulting type
3379
+ // should be determined by Sema::handleFixedPointConversions().
3380
+ QualType ResultTy = op.Ty ;
3381
+ QualType LHSTy = BinOp->getLHS ()->getType ();
3382
+ QualType RHSTy = BinOp->getRHS ()->getType ();
3383
+ ASTContext &Ctx = CGF.getContext ();
3384
+ Value *LHS = op.LHS ;
3385
+ Value *RHS = op.RHS ;
3386
+
3387
+ auto LHSFixedSema = Ctx.getFixedPointSemantics (LHSTy);
3388
+ auto RHSFixedSema = Ctx.getFixedPointSemantics (RHSTy);
3389
+ auto ResultFixedSema = Ctx.getFixedPointSemantics (ResultTy);
3390
+ auto CommonFixedSema = LHSFixedSema.getCommonSemantics (RHSFixedSema);
3391
+
3392
+ // Convert the operands to the full precision type.
3393
+ Value *FullLHS = EmitFixedPointConversion (LHS, LHSFixedSema, CommonFixedSema,
3394
+ BinOp->getExprLoc ());
3395
+ Value *FullRHS = EmitFixedPointConversion (RHS, RHSFixedSema, CommonFixedSema,
3396
+ BinOp->getExprLoc ());
3397
+
3398
+ // Perform the actual addition.
3399
+ Value *Result;
3400
+ if (ResultFixedSema.isSaturated ()) {
3401
+ llvm::Intrinsic::ID IID = ResultFixedSema.isSigned ()
3402
+ ? llvm::Intrinsic::sadd_sat
3403
+ : llvm::Intrinsic::uadd_sat;
3404
+ Result = Builder.CreateBinaryIntrinsic (IID, FullLHS, FullRHS);
3405
+ } else {
3406
+ Result = Builder.CreateAdd (FullLHS, FullRHS);
3407
+ }
3408
+
3409
+ // Convert to the result type.
3410
+ return EmitFixedPointConversion (Result, CommonFixedSema, ResultFixedSema,
3411
+ BinOp->getExprLoc ());
3412
+ }
3413
+
3344
3414
Value *ScalarExprEmitter::EmitSub (const BinOpInfo &op) {
3345
3415
// The LHS is always a pointer if either side is.
3346
3416
if (!op.LHS ->getType ()->isPointerTy ()) {
0 commit comments