xref: /llvm-project/flang/include/flang/Optimizer/CodeGen/Target.h (revision cbb49d4be676a251ca140db92aa2788dd5514569)
1 //===- Target.h - target specific details -----------------------*- C++ -*-===//
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 // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef FORTRAN_OPTMIZER_CODEGEN_TARGET_H
14 #define FORTRAN_OPTMIZER_CODEGEN_TARGET_H
15 
16 #include "flang/Optimizer/Dialect/FIRType.h"
17 #include "flang/Optimizer/Dialect/Support/KindMapping.h"
18 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
19 #include "mlir/IR/BuiltinTypes.h"
20 #include "llvm/TargetParser/Triple.h"
21 #include <memory>
22 #include <tuple>
23 #include <vector>
24 
25 namespace mlir {
26 class DataLayout;
27 }
28 
29 namespace fir {
30 
31 namespace details {
32 /// Extra information about how to marshal an argument or return value that
33 /// modifies a signature per a particular ABI's calling convention.
34 /// Note: llvm::Attribute is not used directly, because its use depends on an
35 /// LLVMContext.
36 class Attributes {
37 public:
38   enum class IntegerExtension { None, Zero, Sign };
39 
40   Attributes(unsigned short alignment = 0, bool byval = false,
41              bool sret = false, bool append = false,
42              IntegerExtension intExt = IntegerExtension::None)
43       : alignment{alignment}, byval{byval}, sret{sret}, append{append},
44         intExt{intExt} {}
45 
46   unsigned getAlignment() const { return alignment; }
47   bool hasAlignment() const { return alignment != 0; }
48   bool isByVal() const { return byval; }
49   bool isSRet() const { return sret; }
50   bool isAppend() const { return append; }
51   bool isZeroExt() const { return intExt == IntegerExtension::Zero; }
52   bool isSignExt() const { return intExt == IntegerExtension::Sign; }
53   llvm::StringRef getIntExtensionAttrName() const;
54 
55 private:
56   unsigned short alignment{};
57   bool byval : 1;
58   bool sret : 1;
59   bool append : 1;
60   IntegerExtension intExt;
61 };
62 
63 } // namespace details
64 
65 /// Some details of how to represent certain features depend on the target and
66 /// ABI that is being used.  These specifics are captured here and guide the
67 /// lowering of FIR to LLVM-IR dialect.
68 class CodeGenSpecifics {
69 public:
70   using Attributes = details::Attributes;
71   using TypeAndAttr = std::tuple<mlir::Type, Attributes>;
72   using Marshalling = std::vector<TypeAndAttr>;
73 
74   static std::unique_ptr<CodeGenSpecifics>
75   get(mlir::MLIRContext *ctx, llvm::Triple &&trp, KindMapping &&kindMap,
76       llvm::StringRef targetCPU, mlir::LLVM::TargetFeaturesAttr targetFeatures,
77       const mlir::DataLayout &dl);
78 
79   static std::unique_ptr<CodeGenSpecifics>
80   get(mlir::MLIRContext *ctx, llvm::Triple &&trp, KindMapping &&kindMap,
81       llvm::StringRef targetCPU, mlir::LLVM::TargetFeaturesAttr targetFeatures,
82       const mlir::DataLayout &dl, llvm::StringRef tuneCPU);
83 
84   static TypeAndAttr getTypeAndAttr(mlir::Type t) { return TypeAndAttr{t, {}}; }
85 
86   CodeGenSpecifics(mlir::MLIRContext *ctx, llvm::Triple &&trp,
87                    KindMapping &&kindMap, llvm::StringRef targetCPU,
88                    mlir::LLVM::TargetFeaturesAttr targetFeatures,
89                    const mlir::DataLayout &dl)
90       : context{*ctx}, triple{std::move(trp)}, kindMap{std::move(kindMap)},
91         targetCPU{targetCPU}, targetFeatures{targetFeatures}, dataLayout{&dl},
92         tuneCPU{""} {}
93 
94   CodeGenSpecifics(mlir::MLIRContext *ctx, llvm::Triple &&trp,
95                    KindMapping &&kindMap, llvm::StringRef targetCPU,
96                    mlir::LLVM::TargetFeaturesAttr targetFeatures,
97                    const mlir::DataLayout &dl, llvm::StringRef tuneCPU)
98       : context{*ctx}, triple{std::move(trp)}, kindMap{std::move(kindMap)},
99         targetCPU{targetCPU}, targetFeatures{targetFeatures}, dataLayout{&dl},
100         tuneCPU{tuneCPU} {}
101 
102   CodeGenSpecifics() = delete;
103   virtual ~CodeGenSpecifics() {}
104 
105   /// Type presentation of a `complex<ele>` type value in memory.
106   virtual mlir::Type complexMemoryType(mlir::Type eleTy) const = 0;
107 
108   /// Type representation of a `complex<eleTy>` type argument when passed by
109   /// value. An argument value may need to be passed as a (safe) reference
110   /// argument.
111   virtual Marshalling complexArgumentType(mlir::Location loc,
112                                           mlir::Type eleTy) const = 0;
113 
114   /// Type representation of a `complex<eleTy>` type return value. Such a return
115   /// value may need to be converted to a hidden reference argument.
116   virtual Marshalling complexReturnType(mlir::Location loc,
117                                         mlir::Type eleTy) const = 0;
118 
119   /// Type presentation of a `boxchar<n>` type value in memory.
120   virtual mlir::Type boxcharMemoryType(mlir::Type eleTy) const = 0;
121 
122   /// Type representation of a `fir.type<T>` type argument when passed by
123   /// value. It may have to be split into several arguments, or be passed
124   /// as a byval reference argument (on the stack).
125   virtual Marshalling
126   structArgumentType(mlir::Location loc, fir::RecordType recTy,
127                      const Marshalling &previousArguments) const = 0;
128 
129   /// Type representation of a `fir.type<T>` type argument when returned by
130   /// value. Such value may need to be converted to a hidden reference argument.
131   virtual Marshalling structReturnType(mlir::Location loc,
132                                        fir::RecordType eleTy) const = 0;
133 
134   /// Type representation of a `boxchar<n>` type argument when passed by value.
135   /// An argument value may need to be passed as a (safe) reference argument.
136   virtual Marshalling boxcharArgumentType(mlir::Type eleTy) const = 0;
137 
138   // Compute ABI rules for an integer argument of the given mlir::IntegerType
139   // \p argTy. Note that this methods is supposed to be called for
140   // arguments passed by value not via reference, e.g. the 'i1' argument here:
141   //   declare i1 @_FortranAioOutputLogical(ptr, i1)
142   //
143   // \p loc is the location of the operation using/specifying the argument.
144   //
145   // Currently, the only supported marshalling is whether the argument
146   // should be zero or sign extended.
147   //
148   // The zero/sign extension is especially important to comply with the ABI
149   // used by C/C++ compiler that builds Fortran runtime. As in the above
150   // example the callee will expect the caller to zero extend the second
151   // argument up to the size of the C/C++'s 'int' type.
152   // The corresponding handling in clang is done in
153   // DefaultABIInfo::classifyArgumentType(), and the logic may brielfy
154   // be explained as some sort of extension is required if the integer
155   // type is shorter than the size of 'int' for the target.
156   // The related code is located in ASTContext::isPromotableIntegerType()
157   // and ABIInfo::isPromotableIntegerTypeForABI().
158   // In particular, the latter returns 'true' for 'bool', several kinds
159   // of 'char', 'short', 'wchar' and enumerated types.
160   // The type of the extensions (zero or sign) depends on the signedness
161   // of the original language type.
162   //
163   // It is not clear how to handle signless integer types.
164   // From the point of Fortran-C interface all supported integer types
165   // seem to be signed except for CFI_type_Bool/bool that is supported
166   // via signless 'i1', but that is treated as unsigned type by clang
167   // (e.g. 'bool' arguments are using 'zeroext' ABI).
168   virtual Marshalling integerArgumentType(mlir::Location loc,
169                                           mlir::IntegerType argTy) const = 0;
170 
171   // By default, integer argument and return values use the same
172   // zero/sign extension rules.
173   virtual Marshalling integerReturnType(mlir::Location loc,
174                                         mlir::IntegerType argTy) const = 0;
175 
176   // Returns width in bits of C/C++ 'int' type size.
177   virtual unsigned char getCIntTypeWidth() const = 0;
178 
179   llvm::StringRef getTargetCPU() const { return targetCPU; }
180   llvm::StringRef getTuneCPU() const { return tuneCPU; }
181 
182   mlir::LLVM::TargetFeaturesAttr getTargetFeatures() const {
183     return targetFeatures;
184   }
185 
186   const mlir::DataLayout &getDataLayout() const {
187     assert(dataLayout && "dataLayout must be set");
188     return *dataLayout;
189   }
190 
191 protected:
192   mlir::MLIRContext &context;
193   llvm::Triple triple;
194   KindMapping kindMap;
195   llvm::StringRef targetCPU;
196   mlir::LLVM::TargetFeaturesAttr targetFeatures;
197   const mlir::DataLayout *dataLayout = nullptr;
198   llvm::StringRef tuneCPU;
199 };
200 
201 } // namespace fir
202 
203 #endif // FORTRAN_OPTMIZER_CODEGEN_TARGET_H
204