MLIR 22.0.0git
APFloatWrappers.cpp
Go to the documentation of this file.
1//===- APFloatWrappers.cpp - Software Implementation of FP Arithmetics --- ===//
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 exposes the APFloat infrastructure to MLIR programs as a runtime
10// library. APFloat is a software implementation of floating point arithmetics.
11//
12// On the MLIR side, floating-point values must be bitcasted to 64-bit integers
13// before calling a runtime function. If a floating-point type has less than
14// 64 bits, it must be zero-extended to 64 bits after bitcasting it to an
15// integer.
16//
17// Runtime functions receive the floating-point operands of the arithmeic
18// operation in the form of 64-bit integers, along with the APFloat semantics
19// in the form of a 32-bit integer, which will be interpreted as an
20// APFloatBase::Semantics enum value.
21//
22#include "llvm/ADT/APFloat.h"
23#include "llvm/ADT/APSInt.h"
24
25#ifdef _WIN32
26#ifndef MLIR_APFLOAT_WRAPPERS_EXPORT
27#ifdef mlir_apfloat_wrappers_EXPORTS
28// We are building this library
29#define MLIR_APFLOAT_WRAPPERS_EXPORT __declspec(dllexport)
30#else
31// We are using this library
32#define MLIR_APFLOAT_WRAPPERS_EXPORT __declspec(dllimport)
33#endif // mlir_apfloat_wrappers_EXPORTS
34#endif // MLIR_APFLOAT_WRAPPERS_EXPORT
35#else
36// Non-windows: use visibility attributes.
37#define MLIR_APFLOAT_WRAPPERS_EXPORT __attribute__((visibility("default")))
38#endif // _WIN32
39
40/// Binary operations without rounding mode.
41#define APFLOAT_BINARY_OP(OP) \
42 MLIR_APFLOAT_WRAPPERS_EXPORT int64_t _mlir_apfloat_##OP( \
43 int32_t semantics, uint64_t a, uint64_t b) { \
44 const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics( \
45 static_cast<llvm::APFloatBase::Semantics>(semantics)); \
46 unsigned bitWidth = llvm::APFloatBase::semanticsSizeInBits(sem); \
47 llvm::APFloat lhs(sem, llvm::APInt(bitWidth, a)); \
48 llvm::APFloat rhs(sem, llvm::APInt(bitWidth, b)); \
49 lhs.OP(rhs); \
50 return lhs.bitcastToAPInt().getZExtValue(); \
51 }
52
53/// Binary operations with rounding mode.
54#define APFLOAT_BINARY_OP_ROUNDING_MODE(OP, ROUNDING_MODE) \
55 MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_##OP( \
56 int32_t semantics, uint64_t a, uint64_t b) { \
57 const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics( \
58 static_cast<llvm::APFloatBase::Semantics>(semantics)); \
59 unsigned bitWidth = llvm::APFloatBase::semanticsSizeInBits(sem); \
60 llvm::APFloat lhs(sem, llvm::APInt(bitWidth, a)); \
61 llvm::APFloat rhs(sem, llvm::APInt(bitWidth, b)); \
62 lhs.OP(rhs, ROUNDING_MODE); \
63 return lhs.bitcastToAPInt().getZExtValue(); \
64 }
65
66extern "C" {
67
68#define BIN_OPS_WITH_ROUNDING(X) \
69 X(add, llvm::RoundingMode::NearestTiesToEven) \
70 X(subtract, llvm::RoundingMode::NearestTiesToEven) \
71 X(multiply, llvm::RoundingMode::NearestTiesToEven) \
72 X(divide, llvm::RoundingMode::NearestTiesToEven)
73
75#undef BIN_OPS_WITH_ROUNDING
76#undef APFLOAT_BINARY_OP_ROUNDING_MODE
77
78APFLOAT_BINARY_OP(remainder)
79
80#undef APFLOAT_BINARY_OP
81
82MLIR_APFLOAT_WRAPPERS_EXPORT void printApFloat(int32_t semantics, uint64_t a) {
83 const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics(
84 static_cast<llvm::APFloatBase::Semantics>(semantics));
85 unsigned bitWidth = llvm::APFloatBase::semanticsSizeInBits(sem);
86 llvm::APFloat x(sem, llvm::APInt(bitWidth, a));
87 double d = x.convertToDouble();
88 fprintf(stdout, "%lg", d);
89}
90
92_mlir_apfloat_convert(int32_t inSemantics, int32_t outSemantics, uint64_t a) {
93 const llvm::fltSemantics &inSem = llvm::APFloatBase::EnumToSemantics(
94 static_cast<llvm::APFloatBase::Semantics>(inSemantics));
95 const llvm::fltSemantics &outSem = llvm::APFloatBase::EnumToSemantics(
96 static_cast<llvm::APFloatBase::Semantics>(outSemantics));
97 unsigned bitWidthIn = llvm::APFloatBase::semanticsSizeInBits(inSem);
98 llvm::APFloat val(inSem, llvm::APInt(bitWidthIn, a));
99 // TODO: Custom rounding modes are not supported yet.
100 bool losesInfo;
101 val.convert(outSem, llvm::RoundingMode::NearestTiesToEven, &losesInfo);
102 llvm::APInt result = val.bitcastToAPInt();
103 return result.getZExtValue();
104}
105
107 int32_t semantics, int32_t resultWidth, bool isUnsigned, uint64_t a) {
108 const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics(
109 static_cast<llvm::APFloatBase::Semantics>(semantics));
110 unsigned inputWidth = llvm::APFloatBase::semanticsSizeInBits(sem);
111 llvm::APFloat val(sem, llvm::APInt(inputWidth, a));
112 llvm::APSInt result(resultWidth, isUnsigned);
113 bool isExact;
114 // TODO: Custom rounding modes are not supported yet.
115 val.convertToInteger(result, llvm::RoundingMode::NearestTiesToEven, &isExact);
116 // This function always returns uint64_t, regardless of the desired result
117 // width. It does not matter whether we zero-extend or sign-extend the APSInt
118 // to 64 bits because the generated IR in arith-to-apfloat will truncate the
119 // result to the desired result width.
120 return result.getZExtValue();
121}
122
124 int32_t semantics, int32_t inputWidth, bool isUnsigned, uint64_t a) {
125 llvm::APInt val(inputWidth, a, /*isSigned=*/!isUnsigned);
126 const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics(
127 static_cast<llvm::APFloatBase::Semantics>(semantics));
128 llvm::APFloat result(sem);
129 // TODO: Custom rounding modes are not supported yet.
130 result.convertFromAPInt(val, /*IsSigned=*/!isUnsigned,
131 llvm::RoundingMode::NearestTiesToEven);
132 return result.bitcastToAPInt().getZExtValue();
133}
134
136 uint64_t a,
137 uint64_t b) {
138 const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics(
139 static_cast<llvm::APFloatBase::Semantics>(semantics));
140 unsigned bitWidth = llvm::APFloatBase::semanticsSizeInBits(sem);
141 llvm::APFloat x(sem, llvm::APInt(bitWidth, a));
142 llvm::APFloat y(sem, llvm::APInt(bitWidth, b));
143 return static_cast<int8_t>(x.compare(y));
144}
145
146MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_neg(int32_t semantics, uint64_t a) {
147 const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics(
148 static_cast<llvm::APFloatBase::Semantics>(semantics));
149 unsigned bitWidth = llvm::APFloatBase::semanticsSizeInBits(sem);
150 llvm::APFloat x(sem, llvm::APInt(bitWidth, a));
151 x.changeSign();
152 return x.bitcastToAPInt().getZExtValue();
153}
154
155/// Min/max operations.
156#define APFLOAT_MIN_MAX_OP(OP) \
157 MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_##OP( \
158 int32_t semantics, uint64_t a, uint64_t b) { \
159 const llvm::fltSemantics &sem = llvm::APFloatBase::EnumToSemantics( \
160 static_cast<llvm::APFloatBase::Semantics>(semantics)); \
161 unsigned bitWidth = llvm::APFloatBase::semanticsSizeInBits(sem); \
162 llvm::APFloat lhs(sem, llvm::APInt(bitWidth, a)); \
163 llvm::APFloat rhs(sem, llvm::APInt(bitWidth, b)); \
164 llvm::APFloat result = llvm::OP(lhs, rhs); \
165 return result.bitcastToAPInt().getZExtValue(); \
166 }
167
168APFLOAT_MIN_MAX_OP(minimum)
169APFLOAT_MIN_MAX_OP(maximum)
170APFLOAT_MIN_MAX_OP(minnum)
171APFLOAT_MIN_MAX_OP(maxnum)
172
173#undef APFLOAT_MIN_MAX_OP
174}
MLIR_APFLOAT_WRAPPERS_EXPORT void printApFloat(int32_t semantics, uint64_t a)
#define APFLOAT_MIN_MAX_OP(OP)
Min/max operations.
#define BIN_OPS_WITH_ROUNDING(X)
MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_convert(int32_t inSemantics, int32_t outSemantics, uint64_t a)
#define APFLOAT_BINARY_OP(OP)
Binary operations without rounding mode.
MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_convert_from_int(int32_t semantics, int32_t inputWidth, bool isUnsigned, uint64_t a)
MLIR_APFLOAT_WRAPPERS_EXPORT int8_t _mlir_apfloat_compare(int32_t semantics, uint64_t a, uint64_t b)
MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_convert_to_int(int32_t semantics, int32_t resultWidth, bool isUnsigned, uint64_t a)
#define APFLOAT_BINARY_OP_ROUNDING_MODE(OP, ROUNDING_MODE)
Binary operations with rounding mode.
#define MLIR_APFLOAT_WRAPPERS_EXPORT
MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_neg(int32_t semantics, uint64_t a)
b
Return true if permutation is a valid permutation of the outer_dims_perm (case OuterOrInnerPerm::Oute...