21 : builder(builder), loc(loc) {}
24 const llvm::FixedPointSemantics &srcSema,
26 mlir::Type opTy = getAccommodatingFloatType(dstTy, srcSema);
30 builder.createCast(loc, cir::CastKind::int_to_float, src, opTy);
33 const llvm::fltSemantics &opSemantics =
34 mlir::cast<cir::FPTypeInterface>(opTy).getFloatSemantics();
35 llvm::APFloat scaleVal(
36 std::pow(2.0, -
static_cast<int>(srcSema.getScale())));
38 scaleVal.convert(opSemantics, llvm::APFloat::rmNearestTiesToEven,
42 cir::ConstantOp fpConst = builder.getConstFP(loc, opTy, scaleVal);
43 result = builder.createFMul(loc, result, fpConst);
46 result = builder.createFloatingCast(result, dstTy);
51 const llvm::FixedPointSemantics &dstSema) {
53 bool useSigned = dstSema.isSigned() || dstSema.hasUnsignedPadding();
54 mlir::Value result = src;
55 mlir::Type opTy = getAccommodatingFloatType(src.getType(), dstSema);
57 if (opTy != src.getType())
58 result = builder.createFloatingCast(result, opTy);
62 const llvm::fltSemantics &opSemantics =
63 mlir::cast<cir::FPTypeInterface>(opTy).getFloatSemantics();
64 llvm::APFloat scaleVal(
std::pow(2.0, dstSema.getScale()));
66 scaleVal.convert(opSemantics, llvm::APFloat::rmNearestTiesToEven,
70 cir::ConstantOp fpConst = builder.getConstFP(loc, opTy, scaleVal);
71 result = builder.createFMul(loc, result, fpConst);
73 cir::IntType resultTy = cir::IntType::get(
74 builder.getContext(), dstSema.getWidth(), dstSema.isSigned());
76 if (dstSema.isSaturated()) {
77 result = builder.emitIntrinsicCallOp(
78 loc, useSigned ?
"fptosi.sat" :
"fptoui.sat", resultTy, result);
80 result = builder.createCast(loc, cir::CastKind::float_to_int, result,
86 if (dstSema.isSaturated() && dstSema.hasUnsignedPadding())
87 result = clampNegativeToZero(result);
93 const llvm::FixedPointSemantics &srcSema,
94 unsigned dstWidth,
bool dstIsSigned) {
97 llvm::FixedPointSemantics::GetIntegerSemantics(dstWidth, dstIsSigned),
102 const llvm::FixedPointSemantics &dstSema) {
104 if (mlir::isa<cir::BoolType>(src.getType())) {
105 assert(!srcIsSigned);
107 src = builder.createBoolToInt(
108 src, cir::IntType::get(builder.getContext(), 1,
false));
110 srcWidth = mlir::cast<cir::IntType>(src.getType()).getWidth();
114 llvm::FixedPointSemantics::GetIntegerSemantics(srcWidth, srcIsSigned),
119 const llvm::FixedPointSemantics &srcSema,
120 const llvm::FixedPointSemantics &dstSema) {
121 return convert(src, srcSema, dstSema,
false);
125 const llvm::FixedPointSemantics &lhsSema,
127 const llvm::FixedPointSemantics &rhsSema) {
128 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
134 commonSema.isSaturated()
135 ? createSaturatingAddSub(wideLhs, wideRhs, commonSema,
137 : builder.createAdd(loc, wideLhs, wideRhs);
140 lhsSema.getCommonSemantics(rhsSema));
144 const llvm::FixedPointSemantics &lhsSema,
146 const llvm::FixedPointSemantics &rhsSema) {
147 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
153 commonSema.isSaturated()
154 ? createSaturatingAddSub(wideLhs, wideRhs, commonSema,
156 : builder.createSub(loc, wideLhs, wideRhs);
159 lhsSema.getCommonSemantics(rhsSema));
163 const llvm::FixedPointSemantics &lhsSema,
165 const llvm::FixedPointSemantics &rhsSema) {
166 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
167 bool useSigned = commonSema.isSigned() || commonSema.hasUnsignedPadding();
173 cir::ConstantOp scale;
176 intrinId =
"smul.fix";
177 scale = builder.getSInt32(commonSema.getScale(), loc);
179 intrinId =
"umul.fix";
180 scale = builder.getUInt32(commonSema.getScale(), loc);
183 if (commonSema.isSaturated())
187 builder.emitIntrinsicCallOp(loc, intrinId, wideLhs.getType(),
188 mlir::ValueRange{wideLhs, wideRhs, scale});
191 lhsSema.getCommonSemantics(rhsSema));
195 const llvm::FixedPointSemantics &lhsSema,
197 const llvm::FixedPointSemantics &rhsSema) {
198 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
199 bool useSigned = commonSema.isSigned() || commonSema.hasUnsignedPadding();
205 cir::ConstantOp scale;
208 intrinId =
"sdiv.fix";
209 scale = builder.getSInt32(commonSema.getScale(), loc);
211 intrinId =
"udiv.fix";
212 scale = builder.getUInt32(commonSema.getScale(), loc);
215 if (commonSema.isSaturated())
219 builder.emitIntrinsicCallOp(loc, intrinId, wideLhs.getType(),
220 mlir::ValueRange{wideLhs, wideRhs, scale});
223 lhsSema.getCommonSemantics(rhsSema));
227 const llvm::FixedPointSemantics &lhsSema,
229 const llvm::FixedPointSemantics &rhsSema,
230 cir::CmpOpKind
kind) {
231 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
236 return builder.createCompare(loc,
kind, wideLhs, wideRhs);
240 const llvm::FixedPointSemantics &lhsSema,
243 if (lhsSema.isSaturated()) {
246 auto rhsIntTy = mlir::cast<cir::IntType>(rhs.getType());
247 auto rhsUnsignedTy = cir::IntType::get(
248 builder.getContext(), rhsIntTy.getWidth(),
false);
250 mlir::Value rhsUnsigned =
251 builder.createCast(cir::CastKind::integral, rhs, rhsUnsignedTy);
252 mlir::Value rhsResized = builder.createCast(cir::CastKind::integral,
253 rhsUnsigned, lhs.getType());
255 bool useSigned = lhsSema.isSigned() || lhsSema.hasUnsignedPadding();
256 result = builder.emitIntrinsicCallOp(
257 loc, useSigned ?
"sshl.sat" :
"ushl.sat", lhs.getType(),
258 mlir::ValueRange{lhs, rhsResized});
260 result = builder.createShiftLeft(loc, lhs, rhs);
266 mlir::Value
createShr(mlir::Value lhs, mlir::Value rhs) {
267 return builder.createShiftRight(loc, lhs, rhs);
271 mlir::Value convert(mlir::Value src,
const llvm::FixedPointSemantics &srcSema,
272 const llvm::FixedPointSemantics &dstSema,
274 unsigned srcWidth = srcSema.getWidth();
275 unsigned dstWidth = dstSema.getWidth();
276 unsigned srcScale = srcSema.getScale();
277 unsigned dstScale = dstSema.getScale();
278 bool srcIsSigned = srcSema.isSigned();
279 bool dstIsSigned = dstSema.isSigned();
281 mlir::Value result = src;
282 unsigned resultWidth = srcWidth;
285 if (dstScale < srcScale) {
289 if (dstIsInteger && srcIsSigned) {
290 mlir::Value zero = builder.
getNullValue(result.getType(), loc);
292 builder.
createCompare(loc, cir::CmpOpKind::lt, result, zero);
294 loc, result.getType(),
295 llvm::APInt::getLowBitsSet(srcWidth, srcScale));
296 mlir::Value rounded = builder.
createAdd(loc, result, lowBits);
302 cir::IntType dstIntTy =
303 cir::IntType::get(builder.getContext(), dstWidth, dstSema.isSigned());
305 if (!dstSema.isSaturated()) {
309 if (dstScale > srcScale)
313 if (dstScale > srcScale) {
315 resultWidth = std::max(srcWidth + dstScale - srcScale, dstWidth);
316 cir::IntType upscaledTy =
317 cir::IntType::get(builder.getContext(), resultWidth, srcIsSigned);
318 result = builder.createIntCast(result, upscaledTy);
319 result = builder.createShiftLeft(loc, result, dstScale - srcScale);
323 bool fewerIntBits = dstSema.getIntegralBits() < srcSema.getIntegralBits();
325 mlir::Value
max = builder.getConstAPInt(
326 loc, result.getType(),
327 llvm::APFixedPoint::getMax(dstSema).getValue().extOrTrunc(
330 mlir::Value tooHigh =
331 builder.createCompare(loc, cir::CmpOpKind::gt, result,
max);
332 result = builder.createSelect(loc, tooHigh,
max, result);
337 if (srcIsSigned && (fewerIntBits || !dstIsSigned)) {
338 mlir::Value
min = builder.getConstAPInt(
339 loc, result.getType(),
340 llvm::APFixedPoint::getMin(dstSema).getValue().extOrTrunc(
343 builder.createCompare(loc, cir::CmpOpKind::lt, result,
min);
344 result = builder.createSelect(loc, tooLow,
min, result);
348 if (resultWidth != dstWidth)
349 result = builder.createIntCast(result, dstIntTy);
354 mlir::Type getAccommodatingFloatType(mlir::Type ty,
355 const llvm::FixedPointSemantics &sema) {
356 const llvm::fltSemantics *floatSema =
357 &mlir::cast<cir::FPTypeInterface>(ty).getFloatSemantics();
358 while (!sema.fitsInFloatSemantics(*floatSema))
359 floatSema = llvm::APFixedPoint::promoteFloatSemantics(floatSema);
360 cir::FPTypeInterface accommodating =
362 assert(accommodating &&
"no float type for semantics?");
363 return accommodating;
367 llvm::FixedPointSemantics
368 getCommonBinopSemantic(
const llvm::FixedPointSemantics &lhsSema,
369 const llvm::FixedPointSemantics &rhsSema) {
370 auto c = lhsSema.getCommonSemantics(rhsSema);
372 lhsSema.hasUnsignedPadding() && rhsSema.hasUnsignedPadding();
373 return llvm::FixedPointSemantics(
374 c.getWidth() +
static_cast<unsigned>(bothPadded && c.isSaturated()),
375 c.getScale(), c.isSigned(), c.isSaturated(), bothPadded);
381 cir::IntType getOpIntType(
const llvm::FixedPointSemantics &sema) {
382 return cir::IntType::get(builder.getContext(), sema.getWidth(),
383 sema.isSigned() || sema.hasUnsignedPadding());
387 mlir::Value clampNegativeToZero(mlir::Value value) {
388 mlir::Value zero = builder.getNullValue(value.getType(), loc);
390 builder.createCompare(loc, cir::CmpOpKind::lt, value, zero);
391 return builder.createSelect(loc, isNeg, zero, value);
394 mlir::Value createSaturatingAddSub(mlir::Value lhs, mlir::Value rhs,
395 const llvm::FixedPointSemantics &sema,
397 cir::IntType opTy = getOpIntType(sema);
398 mlir::Value opLhs = builder.createIntCast(lhs, opTy);
399 mlir::Value opRhs = builder.createIntCast(rhs, opTy);
400 mlir::Value result = isSub ? builder.createSubSat(loc, opLhs, opRhs)
401 : builder.createAddSat(loc, opLhs, opRhs);
402 if (isSub && sema.hasUnsignedPadding())
403 result = clampNegativeToZero(result);
404 return builder.createIntCast(result, lhs.getType());
407 CIRGenBuilderTy &builder;