brintos

brintos / llvm-project-archived public Read only

0
0
Text · 14.5 KiB · 6cf8adb Raw
462 lines · cpp
1//===-- KindMapping.cpp ---------------------------------------------------===//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// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/10//11//===----------------------------------------------------------------------===//12 13#include "flang/Optimizer/Dialect/Support/KindMapping.h"14#include "mlir/Dialect/LLVMIR/LLVMDialect.h"15#include "llvm/IR/LLVMContext.h"16#include "llvm/Support/CommandLine.h"17 18/// Allow the user to set the FIR intrinsic type kind value to LLVM type19/// mappings.  Note that these are not mappings from kind values to any20/// other MLIR dialect, only to LLVM IR. The default values follow the f1821/// front-end kind mappings.22 23using Bitsize = fir::KindMapping::Bitsize;24using KindTy = fir::KindMapping::KindTy;25using LLVMTypeID = fir::KindMapping::LLVMTypeID;26using MatchResult = fir::KindMapping::MatchResult;27 28static llvm::cl::opt<std::string>29    clKindMapping("kind-mapping",30                  llvm::cl::desc("kind mapping string to set kind precision"),31                  llvm::cl::value_desc("kind-mapping-string"),32                  llvm::cl::init(fir::KindMapping::getDefaultMap()));33 34static llvm::cl::opt<std::string>35    clDefaultKinds("default-kinds",36                   llvm::cl::desc("string to set default kind values"),37                   llvm::cl::value_desc("default-kind-string"),38                   llvm::cl::init(fir::KindMapping::getDefaultKinds()));39 40// Keywords for the floating point types.41 42static constexpr const char *kwHalf = "Half";43static constexpr const char *kwBFloat = "BFloat";44static constexpr const char *kwFloat = "Float";45static constexpr const char *kwDouble = "Double";46static constexpr const char *kwX86FP80 = "X86_FP80";47static constexpr const char *kwFP128 = "FP128";48static constexpr const char *kwPPCFP128 = "PPC_FP128";49 50/// Integral types default to the kind value being the size of the value in51/// bytes. The default is to scale from bytes to bits.52static Bitsize defaultScalingKind(KindTy kind) {53  const unsigned bitsInByte = 8;54  return kind * bitsInByte;55}56 57/// Floating-point types default to the kind value being the size of the value58/// in bytes. The default is to translate kinds of 2, 3, 4, 8, 10, and 16 to a59/// valid llvm::Type::TypeID value. Otherwise, the default is FloatTyID.60static LLVMTypeID defaultRealKind(KindTy kind) {61  switch (kind) {62  case 2:63    return LLVMTypeID::HalfTyID;64  case 3:65    return LLVMTypeID::BFloatTyID;66  case 4:67    return LLVMTypeID::FloatTyID;68  case 8:69    return LLVMTypeID::DoubleTyID;70  case 10:71    return LLVMTypeID::X86_FP80TyID;72  case 16:73    return LLVMTypeID::FP128TyID;74  default:75    return LLVMTypeID::FloatTyID;76  }77}78 79// lookup the kind-value given the defaults, the mappings, and a KIND key80template <typename RT, char KEY>81static RT doLookup(std::function<RT(KindTy)> def,82                   const llvm::DenseMap<std::pair<char, KindTy>, RT> &map,83                   KindTy kind) {84  std::pair<char, KindTy> key{KEY, kind};85  auto iter = map.find(key);86  if (iter != map.end())87    return iter->second;88  return def(kind);89}90 91// do a lookup for INTEGER, LOGICAL, or CHARACTER92template <char KEY, typename MAP>93static Bitsize getIntegerLikeBitsize(KindTy kind, const MAP &map) {94  return doLookup<Bitsize, KEY>(defaultScalingKind, map, kind);95}96 97// do a lookup for REAL or COMPLEX98template <char KEY, typename MAP>99static LLVMTypeID getFloatLikeTypeID(KindTy kind, const MAP &map) {100  return doLookup<LLVMTypeID, KEY>(defaultRealKind, map, kind);101}102 103template <char KEY, typename MAP>104static const llvm::fltSemantics &getFloatSemanticsOfKind(KindTy kind,105                                                         const MAP &map) {106  switch (doLookup<LLVMTypeID, KEY>(defaultRealKind, map, kind)) {107  case LLVMTypeID::HalfTyID:108    return llvm::APFloat::IEEEhalf();109  case LLVMTypeID::BFloatTyID:110    return llvm::APFloat::BFloat();111  case LLVMTypeID::FloatTyID:112    return llvm::APFloat::IEEEsingle();113  case LLVMTypeID::DoubleTyID:114    return llvm::APFloat::IEEEdouble();115  case LLVMTypeID::X86_FP80TyID:116    return llvm::APFloat::x87DoubleExtended();117  case LLVMTypeID::FP128TyID:118    return llvm::APFloat::IEEEquad();119  case LLVMTypeID::PPC_FP128TyID:120    return llvm::APFloat::PPCDoubleDouble();121  default:122    llvm_unreachable("Invalid floating type");123  }124}125 126/// Parse an intrinsic type code. The codes are ('a', CHARACTER), ('c',127/// COMPLEX), ('i', INTEGER), ('l', LOGICAL), and ('r', REAL).128static MatchResult parseCode(char &code, const char *&ptr, const char *endPtr) {129  if (ptr >= endPtr)130    return mlir::failure();131  if (*ptr != 'a' && *ptr != 'c' && *ptr != 'i' && *ptr != 'l' && *ptr != 'r')132    return mlir::failure();133  code = *ptr++;134  return mlir::success();135}136 137/// Same as `parseCode` but adds the ('d', DOUBLE PRECISION) code.138static MatchResult parseDefCode(char &code, const char *&ptr,139                                const char *endPtr) {140  if (ptr >= endPtr)141    return mlir::failure();142  if (*ptr == 'd') {143    code = *ptr++;144    return mlir::success();145  }146  return parseCode(code, ptr, endPtr);147}148 149template <char ch>150static MatchResult parseSingleChar(const char *&ptr, const char *endPtr) {151  if (ptr >= endPtr || *ptr != ch)152    return mlir::failure();153  ++ptr;154  return mlir::success();155}156 157static MatchResult parseColon(const char *&ptr, const char *endPtr) {158  return parseSingleChar<':'>(ptr, endPtr);159}160 161static MatchResult parseComma(const char *&ptr, const char *endPtr) {162  return parseSingleChar<','>(ptr, endPtr);163}164 165/// Recognize and parse an unsigned integer.166static MatchResult parseInt(unsigned &result, const char *&ptr,167                            const char *endPtr) {168  const char *beg = ptr;169  while (ptr < endPtr && *ptr >= '0' && *ptr <= '9')170    ptr++;171  if (beg == ptr)172    return mlir::failure();173  llvm::StringRef ref(beg, ptr - beg);174  int temp;175  if (ref.consumeInteger(10, temp))176    return mlir::failure();177  result = temp;178  return mlir::success();179}180 181static llvm::LogicalResult matchString(const char *&ptr, const char *endPtr,182                                       llvm::StringRef literal) {183  llvm::StringRef s(ptr, endPtr - ptr);184  if (s.starts_with(literal)) {185    ptr += literal.size();186    return mlir::success();187  }188  return mlir::failure();189}190 191/// Recognize and parse the various floating-point keywords. These follow the192/// LLVM naming convention.193static MatchResult parseTypeID(LLVMTypeID &result, const char *&ptr,194                               const char *endPtr) {195  if (mlir::succeeded(matchString(ptr, endPtr, kwHalf))) {196    result = LLVMTypeID::HalfTyID;197    return mlir::success();198  }199  if (mlir::succeeded(matchString(ptr, endPtr, kwBFloat))) {200    result = LLVMTypeID::BFloatTyID;201    return mlir::success();202  }203  if (mlir::succeeded(matchString(ptr, endPtr, kwFloat))) {204    result = LLVMTypeID::FloatTyID;205    return mlir::success();206  }207  if (mlir::succeeded(matchString(ptr, endPtr, kwDouble))) {208    result = LLVMTypeID::DoubleTyID;209    return mlir::success();210  }211  if (mlir::succeeded(matchString(ptr, endPtr, kwX86FP80))) {212    result = LLVMTypeID::X86_FP80TyID;213    return mlir::success();214  }215  if (mlir::succeeded(matchString(ptr, endPtr, kwFP128))) {216    result = LLVMTypeID::FP128TyID;217    return mlir::success();218  }219  if (mlir::succeeded(matchString(ptr, endPtr, kwPPCFP128))) {220    result = LLVMTypeID::PPC_FP128TyID;221    return mlir::success();222  }223  return mlir::failure();224}225 226fir::KindMapping::KindMapping(mlir::MLIRContext *context, llvm::StringRef map,227                              llvm::ArrayRef<KindTy> defs)228    : context{context} {229  if (mlir::failed(setDefaultKinds(defs)))230    llvm::report_fatal_error("bad default kinds");231  if (mlir::failed(parse(map)))232    llvm::report_fatal_error("could not parse kind map");233}234 235fir::KindMapping::KindMapping(mlir::MLIRContext *context,236                              llvm::ArrayRef<KindTy> defs)237    : KindMapping{context, clKindMapping, defs} {}238 239fir::KindMapping::KindMapping(mlir::MLIRContext *context)240    : KindMapping{context, clKindMapping, clDefaultKinds} {}241 242MatchResult fir::KindMapping::badMapString(const llvm::Twine &ptr) {243  auto unknown = mlir::UnknownLoc::get(context);244  mlir::emitError(unknown, ptr);245  return mlir::failure();246}247 248MatchResult fir::KindMapping::parse(llvm::StringRef kindMap) {249  if (kindMap.empty())250    return mlir::success();251  const char *srcPtr = kindMap.begin();252  const char *endPtr = kindMap.end();253  while (true) {254    char code = '\0';255    KindTy kind = 0;256    if (parseCode(code, srcPtr, endPtr) || parseInt(kind, srcPtr, endPtr))257      return badMapString(srcPtr);258    if (code == 'a' || code == 'i' || code == 'l') {259      Bitsize bits = 0;260      if (parseColon(srcPtr, endPtr) || parseInt(bits, srcPtr, endPtr))261        return badMapString(srcPtr);262      intMap[std::pair<char, KindTy>{code, kind}] = bits;263    } else if (code == 'r' || code == 'c') {264      LLVMTypeID id{};265      if (parseColon(srcPtr, endPtr) || parseTypeID(id, srcPtr, endPtr))266        return badMapString(srcPtr);267      floatMap[std::pair<char, KindTy>{code, kind}] = id;268    } else {269      return badMapString(srcPtr);270    }271    if (parseComma(srcPtr, endPtr))272      break;273  }274  if (srcPtr > endPtr)275    return badMapString(srcPtr);276  return mlir::success();277}278 279Bitsize fir::KindMapping::getCharacterBitsize(KindTy kind) const {280  return getIntegerLikeBitsize<'a'>(kind, intMap);281}282 283Bitsize fir::KindMapping::getIntegerBitsize(KindTy kind) const {284  return getIntegerLikeBitsize<'i'>(kind, intMap);285}286 287Bitsize fir::KindMapping::getLogicalBitsize(KindTy kind) const {288  return getIntegerLikeBitsize<'l'>(kind, intMap);289}290 291LLVMTypeID fir::KindMapping::getRealTypeID(KindTy kind) const {292  return getFloatLikeTypeID<'r'>(kind, floatMap);293}294 295LLVMTypeID fir::KindMapping::getComplexTypeID(KindTy kind) const {296  return getFloatLikeTypeID<'c'>(kind, floatMap);297}298 299Bitsize fir::KindMapping::getRealBitsize(KindTy kind) const {300  auto typeId = getFloatLikeTypeID<'r'>(kind, floatMap);301  llvm::LLVMContext llCtxt; // FIXME302  return llvm::Type::getPrimitiveType(llCtxt, typeId)->getPrimitiveSizeInBits();303}304 305const llvm::fltSemantics &306fir::KindMapping::getFloatSemantics(KindTy kind) const {307  return getFloatSemanticsOfKind<'r'>(kind, floatMap);308}309 310std::string fir::KindMapping::mapToString() const {311  std::string result;312  bool addComma = false;313  for (auto [k, v] : intMap) {314    if (addComma)315      result.append(",");316    else317      addComma = true;318    result += k.first + std::to_string(k.second) + ":" + std::to_string(v);319  }320  for (auto [k, v] : floatMap) {321    if (addComma)322      result.append(",");323    else324      addComma = true;325    result.append(k.first + std::to_string(k.second) + ":");326    switch (v) {327    default:328      llvm_unreachable("unhandled type-id");329    case LLVMTypeID::HalfTyID:330      result.append(kwHalf);331      break;332    case LLVMTypeID::BFloatTyID:333      result.append(kwBFloat);334      break;335    case LLVMTypeID::FloatTyID:336      result.append(kwFloat);337      break;338    case LLVMTypeID::DoubleTyID:339      result.append(kwDouble);340      break;341    case LLVMTypeID::X86_FP80TyID:342      result.append(kwX86FP80);343      break;344    case LLVMTypeID::FP128TyID:345      result.append(kwFP128);346      break;347    case LLVMTypeID::PPC_FP128TyID:348      result.append(kwPPCFP128);349      break;350    }351  }352  return result;353}354 355llvm::LogicalResult356fir::KindMapping::setDefaultKinds(llvm::ArrayRef<KindTy> defs) {357  if (defs.empty()) {358    // generic front-end defaults359    const KindTy genericKind = 4;360    defaultMap.insert({'a', 1});361    defaultMap.insert({'c', genericKind});362    defaultMap.insert({'d', 2 * genericKind});363    defaultMap.insert({'i', genericKind});364    defaultMap.insert({'l', genericKind});365    defaultMap.insert({'r', genericKind});366    return mlir::success();367  }368  if (defs.size() != 6)369    return mlir::failure();370 371  // defaults determined after command-line processing372  defaultMap.insert({'a', defs[0]});373  defaultMap.insert({'c', defs[1]});374  defaultMap.insert({'d', defs[2]});375  defaultMap.insert({'i', defs[3]});376  defaultMap.insert({'l', defs[4]});377  defaultMap.insert({'r', defs[5]});378  return mlir::success();379}380 381std::string fir::KindMapping::defaultsToString() const {382  return std::string("a") + std::to_string(defaultMap.find('a')->second) +383         std::string("c") + std::to_string(defaultMap.find('c')->second) +384         std::string("d") + std::to_string(defaultMap.find('d')->second) +385         std::string("i") + std::to_string(defaultMap.find('i')->second) +386         std::string("l") + std::to_string(defaultMap.find('l')->second) +387         std::string("r") + std::to_string(defaultMap.find('r')->second);388}389 390/// Convert a default intrinsic code into the proper position in the array. The391/// default kinds have a precise ordering.392static int codeToIndex(char code) {393  switch (code) {394  case 'a':395    return 0;396  case 'c':397    return 1;398  case 'd':399    return 2;400  case 'i':401    return 3;402  case 'l':403    return 4;404  case 'r':405    return 5;406  }407  llvm_unreachable("invalid default kind intrinsic code");408}409 410std::vector<KindTy> fir::KindMapping::toDefaultKinds(llvm::StringRef defs) {411  std::vector<KindTy> result(6);412  char code;413  KindTy kind;414  if (defs.empty())415    defs = clDefaultKinds;416  const char *srcPtr = defs.begin();417  const char *endPtr = defs.end();418  while (srcPtr < endPtr) {419    if (parseDefCode(code, srcPtr, endPtr) || parseInt(kind, srcPtr, endPtr))420      llvm::report_fatal_error("invalid default kind code");421    result[codeToIndex(code)] = kind;422  }423  assert(srcPtr == endPtr);424  return result;425}426 427KindTy fir::KindMapping::defaultCharacterKind() const {428  auto iter = defaultMap.find('a');429  assert(iter != defaultMap.end());430  return iter->second;431}432 433KindTy fir::KindMapping::defaultComplexKind() const {434  auto iter = defaultMap.find('c');435  assert(iter != defaultMap.end());436  return iter->second;437}438 439KindTy fir::KindMapping::defaultDoubleKind() const {440  auto iter = defaultMap.find('d');441  assert(iter != defaultMap.end());442  return iter->second;443}444 445KindTy fir::KindMapping::defaultIntegerKind() const {446  auto iter = defaultMap.find('i');447  assert(iter != defaultMap.end());448  return iter->second;449}450 451KindTy fir::KindMapping::defaultLogicalKind() const {452  auto iter = defaultMap.find('l');453  assert(iter != defaultMap.end());454  return iter->second;455}456 457KindTy fir::KindMapping::defaultRealKind() const {458  auto iter = defaultMap.find('r');459  assert(iter != defaultMap.end());460  return iter->second;461}462