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 mlir::Value zero = builder.getNullValue(result.getType(), loc);
89 builder.createCompare(loc, cir::CmpOpKind::lt, result, zero);
90 result = builder.createSelect(loc, isNeg, zero, result);
97 const llvm::FixedPointSemantics &srcSema,
98 unsigned dstWidth,
bool dstIsSigned) {
101 llvm::FixedPointSemantics::GetIntegerSemantics(dstWidth, dstIsSigned),
106 const llvm::FixedPointSemantics &dstSema) {
108 if (mlir::isa<cir::BoolType>(src.getType())) {
109 assert(!srcIsSigned);
111 src = builder.createBoolToInt(
112 src, cir::IntType::get(builder.getContext(), 1,
false));
114 srcWidth = mlir::cast<cir::IntType>(src.getType()).getWidth();
118 llvm::FixedPointSemantics::GetIntegerSemantics(srcWidth, srcIsSigned),
123 const llvm::FixedPointSemantics &srcSema,
124 const llvm::FixedPointSemantics &dstSema) {
125 return convert(src, srcSema, dstSema,
false);
129 const llvm::FixedPointSemantics &lhsSema,
131 const llvm::FixedPointSemantics &rhsSema) {
132 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
138 if (commonSema.isSaturated()) {
139 result = builder.createAdd(loc, wideLhs, wideRhs,
142 result = builder.createAdd(loc, wideLhs, wideRhs);
146 lhsSema.getCommonSemantics(rhsSema));
150 const llvm::FixedPointSemantics &lhsSema,
152 const llvm::FixedPointSemantics &rhsSema) {
153 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
159 if (commonSema.isSaturated()) {
160 result = builder.createSub(loc, wideLhs, wideRhs,
163 result = builder.createSub(loc, wideLhs, wideRhs);
168 if (commonSema.isSaturated() && commonSema.hasUnsignedPadding()) {
169 mlir::Value zero = builder.getNullValue(result.getType(), loc);
171 builder.createCompare(loc, cir::CmpOpKind::lt, result, zero);
172 result = builder.createSelect(loc, ltZero, zero, result);
176 lhsSema.getCommonSemantics(rhsSema));
180 const llvm::FixedPointSemantics &lhsSema,
182 const llvm::FixedPointSemantics &rhsSema) {
183 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
184 bool useSigned = commonSema.isSigned() || commonSema.hasUnsignedPadding();
190 cir::ConstantOp scale;
193 intrinId =
"smul.fix";
194 scale = builder.getSInt32(commonSema.getScale(), loc);
196 intrinId =
"umul.fix";
197 scale = builder.getUInt32(commonSema.getScale(), loc);
200 if (commonSema.isSaturated())
204 builder.emitIntrinsicCallOp(loc, intrinId, wideLhs.getType(),
205 mlir::ValueRange{wideLhs, wideRhs, scale});
208 lhsSema.getCommonSemantics(rhsSema));
212 const llvm::FixedPointSemantics &lhsSema,
214 const llvm::FixedPointSemantics &rhsSema) {
215 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
216 bool useSigned = commonSema.isSigned() || commonSema.hasUnsignedPadding();
222 cir::ConstantOp scale;
225 intrinId =
"sdiv.fix";
226 scale = builder.getSInt32(commonSema.getScale(), loc);
228 intrinId =
"udiv.fix";
229 scale = builder.getUInt32(commonSema.getScale(), loc);
232 if (commonSema.isSaturated())
236 builder.emitIntrinsicCallOp(loc, intrinId, wideLhs.getType(),
237 mlir::ValueRange{wideLhs, wideRhs, scale});
240 lhsSema.getCommonSemantics(rhsSema));
244 const llvm::FixedPointSemantics &lhsSema,
246 const llvm::FixedPointSemantics &rhsSema,
247 cir::CmpOpKind
kind) {
248 auto commonSema = getCommonBinopSemantic(lhsSema, rhsSema);
253 return builder.createCompare(loc,
kind, wideLhs, wideRhs);
257 const llvm::FixedPointSemantics &lhsSema,
260 if (lhsSema.isSaturated()) {
263 auto rhsIntTy = mlir::cast<cir::IntType>(rhs.getType());
264 auto rhsUnsignedTy = cir::IntType::get(
265 builder.getContext(), rhsIntTy.getWidth(),
false);
267 mlir::Value rhsUnsigned =
268 builder.createCast(cir::CastKind::integral, rhs, rhsUnsignedTy);
269 mlir::Value rhsResized = builder.createCast(cir::CastKind::integral,
270 rhsUnsigned, lhs.getType());
272 bool useSigned = lhsSema.isSigned() || lhsSema.hasUnsignedPadding();
273 result = builder.emitIntrinsicCallOp(
274 loc, useSigned ?
"sshl.sat" :
"ushl.sat", lhs.getType(),
275 mlir::ValueRange{lhs, rhsResized});
277 result = builder.createShiftLeft(loc, lhs, rhs);
283 mlir::Value
createShr(mlir::Value lhs, mlir::Value rhs) {
284 return builder.createShiftRight(loc, lhs, rhs);
288 mlir::Value convert(mlir::Value src,
const llvm::FixedPointSemantics &srcSema,
289 const llvm::FixedPointSemantics &dstSema,
291 unsigned srcWidth = srcSema.getWidth();
292 unsigned dstWidth = dstSema.getWidth();
293 unsigned srcScale = srcSema.getScale();
294 unsigned dstScale = dstSema.getScale();
295 bool srcIsSigned = srcSema.isSigned();
296 bool dstIsSigned = dstSema.isSigned();
298 mlir::Value result = src;
299 unsigned resultWidth = srcWidth;
302 if (dstScale < srcScale) {
306 if (dstIsInteger && srcIsSigned) {
307 mlir::Value zero = builder.
getNullValue(result.getType(), loc);
309 builder.
createCompare(loc, cir::CmpOpKind::lt, result, zero);
311 loc, result.getType(),
312 llvm::APInt::getLowBitsSet(srcWidth, srcScale));
313 mlir::Value rounded = builder.
createAdd(loc, result, lowBits);
319 cir::IntType dstIntTy =
320 cir::IntType::get(builder.getContext(), dstWidth, dstSema.isSigned());
322 if (!dstSema.isSaturated()) {
326 if (dstScale > srcScale)
330 if (dstScale > srcScale) {
332 resultWidth = std::max(srcWidth + dstScale - srcScale, dstWidth);
333 cir::IntType upscaledTy =
334 cir::IntType::get(builder.getContext(), resultWidth, srcIsSigned);
335 result = builder.createIntCast(result, upscaledTy);
336 result = builder.createShiftLeft(loc, result, dstScale - srcScale);
340 bool fewerIntBits = dstSema.getIntegralBits() < srcSema.getIntegralBits();
342 mlir::Value
max = builder.getConstAPInt(
343 loc, result.getType(),
344 llvm::APFixedPoint::getMax(dstSema).getValue().extOrTrunc(
347 mlir::Value tooHigh =
348 builder.createCompare(loc, cir::CmpOpKind::gt, result,
max);
349 result = builder.createSelect(loc, tooHigh,
max, result);
354 if (srcIsSigned && (fewerIntBits || !dstIsSigned)) {
355 mlir::Value
min = builder.getConstAPInt(
356 loc, result.getType(),
357 llvm::APFixedPoint::getMin(dstSema).getValue().extOrTrunc(
360 builder.createCompare(loc, cir::CmpOpKind::lt, result,
min);
361 result = builder.createSelect(loc, tooLow,
min, result);
365 if (resultWidth != dstWidth)
366 result = builder.createIntCast(result, dstIntTy);
371 mlir::Type getAccommodatingFloatType(mlir::Type ty,
372 const llvm::FixedPointSemantics &sema) {
373 const llvm::fltSemantics *floatSema =
374 &mlir::cast<cir::FPTypeInterface>(ty).getFloatSemantics();
375 while (!sema.fitsInFloatSemantics(*floatSema))
376 floatSema = llvm::APFixedPoint::promoteFloatSemantics(floatSema);
377 cir::FPTypeInterface accommodating =
379 assert(accommodating &&
"no float type for semantics?");
380 return accommodating;
384 llvm::FixedPointSemantics
385 getCommonBinopSemantic(
const llvm::FixedPointSemantics &lhsSema,
386 const llvm::FixedPointSemantics &rhsSema) {
387 auto c = lhsSema.getCommonSemantics(rhsSema);
389 lhsSema.hasUnsignedPadding() && rhsSema.hasUnsignedPadding();
390 return llvm::FixedPointSemantics(
391 c.getWidth() +
static_cast<unsigned>(bothPadded && c.isSaturated()),
392 c.getScale(), c.isSigned(), c.isSaturated(), bothPadded);
395 CIRGenBuilderTy &builder;