175 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file exposes the APFloat infrastructure to MLIR programs as a runtime10// 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 integers13// before calling a runtime function. If a floating-point type has less than14// 64 bits, it must be zero-extended to 64 bits after bitcasting it to an15// integer.16//17// Runtime functions receive the floating-point operands of the arithmeic18// operation in the form of 64-bit integers, along with the APFloat semantics19// in the form of a 32-bit integer, which will be interpreted as an20// APFloatBase::Semantics enum value.21//22#include "llvm/ADT/APFloat.h"23#include "llvm/ADT/APSInt.h"24 25#ifdef _WIN3226#ifndef MLIR_APFLOAT_WRAPPERS_EXPORT27#ifdef mlir_apfloat_wrappers_EXPORTS28// We are building this library29#define MLIR_APFLOAT_WRAPPERS_EXPORT __declspec(dllexport)30#else31// We are using this library32#define MLIR_APFLOAT_WRAPPERS_EXPORT __declspec(dllimport)33#endif // mlir_apfloat_wrappers_EXPORTS34#endif // MLIR_APFLOAT_WRAPPERS_EXPORT35#else36// Non-windows: use visibility attributes.37#define MLIR_APFLOAT_WRAPPERS_EXPORT __attribute__((visibility("default")))38#endif // _WIN3239 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 74BIN_OPS_WITH_ROUNDING(APFLOAT_BINARY_OP_ROUNDING_MODE)75#undef BIN_OPS_WITH_ROUNDING76#undef APFLOAT_BINARY_OP_ROUNDING_MODE77 78APFLOAT_BINARY_OP(remainder)79 80#undef APFLOAT_BINARY_OP81 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 91MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t92_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 106MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_convert_to_int(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 result117 // width. It does not matter whether we zero-extend or sign-extend the APSInt118 // to 64 bits because the generated IR in arith-to-apfloat will truncate the119 // result to the desired result width.120 return result.getZExtValue();121}122 123MLIR_APFLOAT_WRAPPERS_EXPORT uint64_t _mlir_apfloat_convert_from_int(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 135MLIR_APFLOAT_WRAPPERS_EXPORT int8_t _mlir_apfloat_compare(int32_t semantics,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_OP174}175