1 //===-- FIRBuilder.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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "flang/Lower/FIRBuilder.h"
10 #include "SymbolMap.h"
11 #include "flang/Lower/Bridge.h"
12 #include "flang/Lower/ComplexExpr.h"
13 #include "flang/Lower/ConvertType.h"
14 #include "flang/Optimizer/Dialect/FIROpsSupport.h"
15 #include "flang/Semantics/symbol.h"
16 #include "llvm/Support/ErrorHandling.h"
17 
createFunction(mlir::Location loc,mlir::ModuleOp module,llvm::StringRef name,mlir::FunctionType ty)18 mlir::FuncOp Fortran::lower::FirOpBuilder::createFunction(
19     mlir::Location loc, mlir::ModuleOp module, llvm::StringRef name,
20     mlir::FunctionType ty) {
21   return fir::createFuncOp(loc, module, name, ty);
22 }
23 
24 mlir::FuncOp
getNamedFunction(mlir::ModuleOp modOp,llvm::StringRef name)25 Fortran::lower::FirOpBuilder::getNamedFunction(mlir::ModuleOp modOp,
26                                                llvm::StringRef name) {
27   return modOp.lookupSymbol<mlir::FuncOp>(name);
28 }
29 
30 fir::GlobalOp
getNamedGlobal(mlir::ModuleOp modOp,llvm::StringRef name)31 Fortran::lower::FirOpBuilder::getNamedGlobal(mlir::ModuleOp modOp,
32                                              llvm::StringRef name) {
33   return modOp.lookupSymbol<fir::GlobalOp>(name);
34 }
35 
getRefType(mlir::Type eleTy)36 mlir::Type Fortran::lower::FirOpBuilder::getRefType(mlir::Type eleTy) {
37   assert(!eleTy.isa<fir::ReferenceType>());
38   return fir::ReferenceType::get(eleTy);
39 }
40 
41 mlir::Value
createNullConstant(mlir::Location loc)42 Fortran::lower::FirOpBuilder::createNullConstant(mlir::Location loc) {
43   auto indexType = getIndexType();
44   auto zero = createIntegerConstant(loc, indexType, 0);
45   auto noneRefType = getRefType(getNoneType());
46   return createConvert(loc, noneRefType, zero);
47 }
48 
createIntegerConstant(mlir::Location loc,mlir::Type ty,std::int64_t cst)49 mlir::Value Fortran::lower::FirOpBuilder::createIntegerConstant(
50     mlir::Location loc, mlir::Type ty, std::int64_t cst) {
51   return create<mlir::ConstantOp>(loc, ty, getIntegerAttr(ty, cst));
52 }
53 
createRealConstant(mlir::Location loc,mlir::Type realType,const llvm::APFloat & val)54 mlir::Value Fortran::lower::FirOpBuilder::createRealConstant(
55     mlir::Location loc, mlir::Type realType, const llvm::APFloat &val) {
56   return create<mlir::ConstantOp>(loc, realType, getFloatAttr(realType, val));
57 }
58 
59 mlir::Value
createRealZeroConstant(mlir::Location loc,mlir::Type realType)60 Fortran::lower::FirOpBuilder::createRealZeroConstant(mlir::Location loc,
61                                                      mlir::Type realType) {
62   mlir::Attribute attr;
63   if (auto firType = realType.dyn_cast<fir::RealType>()) {
64     attr = getFloatAttr(
65         realType,
66         llvm::APFloat(kindMap.getFloatSemantics(firType.getFKind()), 0));
67   } else { // mlir::FloatType.
68     attr = getZeroAttr(realType);
69   }
70   return create<mlir::ConstantOp>(loc, realType, attr);
71 }
72 
allocateLocal(mlir::Location loc,mlir::Type ty,llvm::StringRef nm,llvm::ArrayRef<mlir::Value> shape,bool asTarget)73 mlir::Value Fortran::lower::FirOpBuilder::allocateLocal(
74     mlir::Location loc, mlir::Type ty, llvm::StringRef nm,
75     llvm::ArrayRef<mlir::Value> shape, bool asTarget) {
76   llvm::SmallVector<mlir::Value, 8> indices;
77   auto idxTy = getIndexType();
78   llvm::for_each(shape, [&](mlir::Value sh) {
79     indices.push_back(createConvert(loc, idxTy, sh));
80   });
81   llvm::SmallVector<mlir::NamedAttribute, 2> attrs;
82   if (asTarget)
83     attrs.emplace_back(mlir::Identifier::get("target", getContext()),
84                        getUnitAttr());
85   return create<fir::AllocaOp>(loc, ty, nm, llvm::None, indices, attrs);
86 }
87 
88 /// Create a temporary variable on the stack. Anonymous temporaries have no
89 /// `name` value.
createTemporary(mlir::Location loc,mlir::Type type,llvm::StringRef name,llvm::ArrayRef<mlir::Value> shape)90 mlir::Value Fortran::lower::FirOpBuilder::createTemporary(
91     mlir::Location loc, mlir::Type type, llvm::StringRef name,
92     llvm::ArrayRef<mlir::Value> shape) {
93   auto insPt = saveInsertionPoint();
94   if (shape.empty())
95     setInsertionPointToStart(getEntryBlock());
96   else
97     setInsertionPointAfter(shape.back().getDefiningOp());
98   assert(!type.isa<fir::ReferenceType>() && "cannot be a reference");
99   auto ae = create<fir::AllocaOp>(loc, type, name, llvm::None, shape);
100   restoreInsertionPoint(insPt);
101   return ae;
102 }
103 
104 /// Create a global variable in the (read-only) data section. A global variable
105 /// must have a unique name to identify and reference it.
createGlobal(mlir::Location loc,mlir::Type type,llvm::StringRef name,mlir::StringAttr linkage,mlir::Attribute value,bool isConst)106 fir::GlobalOp Fortran::lower::FirOpBuilder::createGlobal(
107     mlir::Location loc, mlir::Type type, llvm::StringRef name,
108     mlir::StringAttr linkage, mlir::Attribute value, bool isConst) {
109   auto module = getModule();
110   auto insertPt = saveInsertionPoint();
111   if (auto glob = module.lookupSymbol<fir::GlobalOp>(name))
112     return glob;
113   setInsertionPoint(module.getBody()->getTerminator());
114   auto glob = create<fir::GlobalOp>(loc, name, isConst, type, value, linkage);
115   restoreInsertionPoint(insertPt);
116   return glob;
117 }
118 
createGlobal(mlir::Location loc,mlir::Type type,llvm::StringRef name,bool isConst,std::function<void (FirOpBuilder &)> bodyBuilder,mlir::StringAttr linkage)119 fir::GlobalOp Fortran::lower::FirOpBuilder::createGlobal(
120     mlir::Location loc, mlir::Type type, llvm::StringRef name, bool isConst,
121     std::function<void(FirOpBuilder &)> bodyBuilder, mlir::StringAttr linkage) {
122   auto module = getModule();
123   auto insertPt = saveInsertionPoint();
124   if (auto glob = module.lookupSymbol<fir::GlobalOp>(name))
125     return glob;
126   setInsertionPoint(module.getBody()->getTerminator());
127   auto glob = create<fir::GlobalOp>(loc, name, isConst, type, mlir::Attribute{},
128                                     linkage);
129   auto &region = glob.getRegion();
130   region.push_back(new mlir::Block);
131   auto &block = glob.getRegion().back();
132   setInsertionPointToStart(&block);
133   bodyBuilder(*this);
134   restoreInsertionPoint(insertPt);
135   return glob;
136 }
137 
convertWithSemantics(mlir::Location loc,mlir::Type toTy,mlir::Value val)138 mlir::Value Fortran::lower::FirOpBuilder::convertWithSemantics(
139     mlir::Location loc, mlir::Type toTy, mlir::Value val) {
140   assert(toTy && "store location must be typed");
141   auto fromTy = val.getType();
142   if (fromTy == toTy)
143     return val;
144   // FIXME: add a fir::is_integer() test
145   ComplexExprHelper helper{*this, loc};
146   if ((fir::isa_real(fromTy) || fromTy.isSignlessInteger()) &&
147       fir::isa_complex(toTy)) {
148     // imaginary part is zero
149     auto eleTy = helper.getComplexPartType(toTy);
150     auto cast = createConvert(loc, eleTy, val);
151     llvm::APFloat zero{
152         kindMap.getFloatSemantics(toTy.cast<fir::ComplexType>().getFKind()), 0};
153     auto imag = createRealConstant(loc, eleTy, zero);
154     return helper.createComplex(toTy, cast, imag);
155   }
156   // FIXME: add a fir::is_integer() test
157   if (fir::isa_complex(fromTy) &&
158       (toTy.isSignlessInteger() || fir::isa_real(toTy))) {
159     // drop the imaginary part
160     auto rp = helper.extractComplexPart(val, /*isImagPart=*/false);
161     return createConvert(loc, toTy, rp);
162   }
163   return createConvert(loc, toTy, val);
164 }
165 
createConvert(mlir::Location loc,mlir::Type toTy,mlir::Value val)166 mlir::Value Fortran::lower::FirOpBuilder::createConvert(mlir::Location loc,
167                                                         mlir::Type toTy,
168                                                         mlir::Value val) {
169   if (val.getType() != toTy)
170     return create<fir::ConvertOp>(loc, toTy, val);
171   return val;
172 }
173 
createStringLit(mlir::Location loc,mlir::Type eleTy,llvm::StringRef data)174 fir::StringLitOp Fortran::lower::FirOpBuilder::createStringLit(
175     mlir::Location loc, mlir::Type eleTy, llvm::StringRef data) {
176   auto strAttr = mlir::StringAttr::get(getContext(), data);
177   auto valTag = mlir::Identifier::get(fir::StringLitOp::value(), getContext());
178   mlir::NamedAttribute dataAttr(valTag, strAttr);
179   auto sizeTag = mlir::Identifier::get(fir::StringLitOp::size(), getContext());
180   mlir::NamedAttribute sizeAttr(sizeTag, getI64IntegerAttr(data.size()));
181   llvm::SmallVector<mlir::NamedAttribute, 2> attrs{dataAttr, sizeAttr};
182   auto arrTy =
183       fir::SequenceType::get(fir::SequenceType::Shape(1, data.size()), eleTy);
184   return create<fir::StringLitOp>(loc, llvm::ArrayRef<mlir::Type>{arrTy},
185                                   llvm::None, attrs);
186 }
187