-
Notifications
You must be signed in to change notification settings - Fork 12.6k
/
Copy pathFIRBuilder.h
755 lines (622 loc) · 33.3 KB
/
FIRBuilder.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
//===-- FirBuilder.h -- FIR operation builder -------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Builder routines for constructing the FIR dialect of MLIR. As FIR is a
// dialect of MLIR, it makes extensive use of MLIR interfaces and MLIR's coding
// style (https://mlir.llvm.org/getting_started/DeveloperGuide/) is used in this
// module.
//
//===----------------------------------------------------------------------===//
#ifndef FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H
#define FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H
#include "flang/Common/MathOptionsBase.h"
#include "flang/Optimizer/Dialect/FIROps.h"
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
#include "flang/Optimizer/Dialect/Support/KindMapping.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "llvm/ADT/DenseMap.h"
#include <optional>
#include <utility>
namespace mlir {
class DataLayout;
class SymbolTable;
}
namespace fir {
class AbstractArrayBox;
class ExtendedValue;
class MutableBoxValue;
class BoxValue;
/// Get the integer type with a pointer size.
inline mlir::Type getIntPtrType(mlir::OpBuilder &builder) {
// TODO: Delay the need of such type until codegen or find a way to use
// llvm::DataLayout::getPointerSizeInBits here.
return builder.getI64Type();
}
//===----------------------------------------------------------------------===//
// FirOpBuilder
//===----------------------------------------------------------------------===//
/// Extends the MLIR OpBuilder to provide methods for building common FIR
/// patterns.
class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
public:
explicit FirOpBuilder(mlir::Operation *op, fir::KindMapping kindMap,
mlir::SymbolTable *symbolTable = nullptr)
: OpBuilder{op, /*listener=*/this}, kindMap{std::move(kindMap)},
symbolTable{symbolTable} {}
explicit FirOpBuilder(mlir::OpBuilder &builder, fir::KindMapping kindMap,
mlir::SymbolTable *symbolTable = nullptr)
: OpBuilder(builder), OpBuilder::Listener(), kindMap{std::move(kindMap)},
symbolTable{symbolTable} {
setListener(this);
}
explicit FirOpBuilder(mlir::OpBuilder &builder, mlir::ModuleOp mod)
: OpBuilder(builder), OpBuilder::Listener(),
kindMap{getKindMapping(mod)} {
setListener(this);
}
explicit FirOpBuilder(mlir::OpBuilder &builder, fir::KindMapping kindMap,
mlir::Operation *op)
: OpBuilder(builder), OpBuilder::Listener(), kindMap{std::move(kindMap)} {
setListener(this);
auto fmi = mlir::dyn_cast<mlir::arith::ArithFastMathInterface>(*op);
if (fmi) {
// Set the builder with FastMathFlags attached to the operation.
setFastMathFlags(fmi.getFastMathFlagsAttr().getValue());
}
}
FirOpBuilder(mlir::OpBuilder &builder, mlir::Operation *op)
: FirOpBuilder(builder, fir::getKindMapping(op), op) {}
// The listener self-reference has to be updated in case of copy-construction.
FirOpBuilder(const FirOpBuilder &other)
: OpBuilder(other), OpBuilder::Listener(), kindMap{other.kindMap},
fastMathFlags{other.fastMathFlags}, symbolTable{other.symbolTable} {
setListener(this);
}
FirOpBuilder(FirOpBuilder &&other)
: OpBuilder(other), OpBuilder::Listener(),
kindMap{std::move(other.kindMap)}, fastMathFlags{other.fastMathFlags},
symbolTable{other.symbolTable} {
setListener(this);
}
/// Get the current Region of the insertion point.
mlir::Region &getRegion() { return *getBlock()->getParent(); }
/// Get the current Module
mlir::ModuleOp getModule() {
return getRegion().getParentOfType<mlir::ModuleOp>();
}
/// Get the current Function
mlir::func::FuncOp getFunction() {
return getRegion().getParentOfType<mlir::func::FuncOp>();
}
/// Get a reference to the kind map.
const fir::KindMapping &getKindMap() { return kindMap; }
/// Get func.func/fir.global symbol table attached to this builder if any.
mlir::SymbolTable *getMLIRSymbolTable() { return symbolTable; }
/// Get the default integer type
[[maybe_unused]] mlir::IntegerType getDefaultIntegerType() {
return getIntegerType(
getKindMap().getIntegerBitsize(getKindMap().defaultIntegerKind()));
}
/// The LHS and RHS are not always in agreement in terms of type. In some
/// cases, the disagreement is between COMPLEX and other scalar types. In that
/// case, the conversion must insert (extract) out of a COMPLEX value to have
/// the proper semantics and be strongly typed. E.g., converting an integer
/// (real) to a complex, the real part is filled using the integer (real)
/// after type conversion and the imaginary part is zero.
mlir::Value convertWithSemantics(mlir::Location loc, mlir::Type toTy,
mlir::Value val,
bool allowCharacterConversion = false,
bool allowRebox = false);
/// Get the entry block of the current Function
mlir::Block *getEntryBlock() { return &getFunction().front(); }
/// Get the block for adding Allocas. If OpenMP is enabled then get the
/// the alloca block from an Operation which can be Outlined. Otherwise
/// use the entry block of the current Function
mlir::Block *getAllocaBlock();
/// Safely create a reference type to the type `eleTy`.
mlir::Type getRefType(mlir::Type eleTy);
/// Create a sequence of `eleTy` with `rank` dimensions of unknown size.
mlir::Type getVarLenSeqTy(mlir::Type eleTy, unsigned rank = 1);
/// Get character length type.
mlir::Type getCharacterLengthType() { return getIndexType(); }
/// Get the integer type whose bit width corresponds to the width of pointer
/// types, or is bigger.
mlir::Type getIntPtrType() { return fir::getIntPtrType(*this); }
/// Wrap `str` to a SymbolRefAttr.
mlir::SymbolRefAttr getSymbolRefAttr(llvm::StringRef str) {
return mlir::SymbolRefAttr::get(getContext(), str);
}
/// Get the mlir float type that implements Fortran REAL(kind).
mlir::Type getRealType(int kind);
fir::BoxProcType getBoxProcType(mlir::FunctionType funcTy) {
return fir::BoxProcType::get(getContext(), funcTy);
}
/// Create a null constant memory reference of type \p ptrType.
/// If \p ptrType is not provided, !fir.ref<none> type will be used.
mlir::Value createNullConstant(mlir::Location loc, mlir::Type ptrType = {});
/// Create an integer constant of type \p type and value \p i.
/// Should not be used with negative values with integer types of more
/// than 64 bits.
mlir::Value createIntegerConstant(mlir::Location loc, mlir::Type integerType,
std::int64_t i);
/// Create an integer of \p integerType where all the bits have been set to
/// ones. Safe to use regardless of integerType bitwidth.
mlir::Value createAllOnesInteger(mlir::Location loc, mlir::Type integerType);
/// Create -1 constant of \p integerType. Safe to use regardless of
/// integerType bitwidth.
mlir::Value createMinusOneInteger(mlir::Location loc,
mlir::Type integerType) {
return createAllOnesInteger(loc, integerType);
}
/// Create a real constant from an integer value.
mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
llvm::APFloat::integerPart val);
/// Create a real constant from an APFloat value.
mlir::Value createRealConstant(mlir::Location loc, mlir::Type realType,
const llvm::APFloat &val);
/// Create a real constant of type \p realType with a value zero.
mlir::Value createRealZeroConstant(mlir::Location loc, mlir::Type realType) {
return createRealConstant(loc, realType, 0u);
}
/// Create a slot for a local on the stack. Besides the variable's type and
/// shape, it may be given name, pinned, or target attributes.
mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty,
llvm::StringRef uniqName, llvm::StringRef name,
bool pinned, llvm::ArrayRef<mlir::Value> shape,
llvm::ArrayRef<mlir::Value> lenParams,
bool asTarget = false);
mlir::Value allocateLocal(mlir::Location loc, mlir::Type ty,
llvm::StringRef uniqName, llvm::StringRef name,
llvm::ArrayRef<mlir::Value> shape,
llvm::ArrayRef<mlir::Value> lenParams,
bool asTarget = false);
/// Create a temporary using `fir.alloca`. This function does not hoist.
/// It is the callers responsibility to set the insertion point if
/// hoisting is required.
mlir::Value createTemporaryAlloc(
mlir::Location loc, mlir::Type type, llvm::StringRef name,
mlir::ValueRange lenParams = {}, mlir::ValueRange shape = {},
llvm::ArrayRef<mlir::NamedAttribute> attrs = {},
std::optional<Fortran::common::CUDADataAttr> cudaAttr = std::nullopt);
/// Create a temporary. A temp is allocated using `fir.alloca` and can be read
/// and written using `fir.load` and `fir.store`, resp. The temporary can be
/// given a name via a front-end `Symbol` or a `StringRef`.
mlir::Value createTemporary(
mlir::Location loc, mlir::Type type, llvm::StringRef name = {},
mlir::ValueRange shape = {}, mlir::ValueRange lenParams = {},
llvm::ArrayRef<mlir::NamedAttribute> attrs = {},
std::optional<Fortran::common::CUDADataAttr> cudaAttr = std::nullopt);
/// Create an unnamed and untracked temporary on the stack.
mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
mlir::ValueRange shape) {
return createTemporary(loc, type, llvm::StringRef{}, shape);
}
mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
llvm::ArrayRef<mlir::NamedAttribute> attrs) {
return createTemporary(loc, type, llvm::StringRef{}, {}, {}, attrs);
}
mlir::Value createTemporary(mlir::Location loc, mlir::Type type,
llvm::StringRef name,
llvm::ArrayRef<mlir::NamedAttribute> attrs) {
return createTemporary(loc, type, name, {}, {}, attrs);
}
/// Create a temporary on the heap.
mlir::Value
createHeapTemporary(mlir::Location loc, mlir::Type type,
llvm::StringRef name = {}, mlir::ValueRange shape = {},
mlir::ValueRange lenParams = {},
llvm::ArrayRef<mlir::NamedAttribute> attrs = {});
/// Create an LLVM stack save intrinsic op. Returns the saved stack pointer.
/// The stack address space is fetched from the data layout of the current
/// module.
mlir::Value genStackSave(mlir::Location loc);
/// Create an LLVM stack restore intrinsic op. stackPointer should be a value
/// previously returned from genStackSave.
void genStackRestore(mlir::Location loc, mlir::Value stackPointer);
/// Create a global value.
fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
llvm::StringRef name,
mlir::StringAttr linkage = {},
mlir::Attribute value = {}, bool isConst = false,
bool isTarget = false,
cuf::DataAttributeAttr dataAttr = {});
fir::GlobalOp createGlobal(mlir::Location loc, mlir::Type type,
llvm::StringRef name, bool isConst, bool isTarget,
std::function<void(FirOpBuilder &)> bodyBuilder,
mlir::StringAttr linkage = {},
cuf::DataAttributeAttr dataAttr = {});
/// Create a global constant (read-only) value.
fir::GlobalOp createGlobalConstant(mlir::Location loc, mlir::Type type,
llvm::StringRef name,
mlir::StringAttr linkage = {},
mlir::Attribute value = {}) {
return createGlobal(loc, type, name, linkage, value, /*isConst=*/true,
/*isTarget=*/false);
}
fir::GlobalOp
createGlobalConstant(mlir::Location loc, mlir::Type type,
llvm::StringRef name,
std::function<void(FirOpBuilder &)> bodyBuilder,
mlir::StringAttr linkage = {}) {
return createGlobal(loc, type, name, /*isConst=*/true, /*isTarget=*/false,
bodyBuilder, linkage);
}
/// Convert a StringRef string into a fir::StringLitOp.
fir::StringLitOp createStringLitOp(mlir::Location loc,
llvm::StringRef string);
std::pair<fir::TypeInfoOp, mlir::OpBuilder::InsertPoint>
createTypeInfoOp(mlir::Location loc, fir::RecordType recordType,
fir::RecordType parentType);
//===--------------------------------------------------------------------===//
// Linkage helpers (inline). The default linkage is external.
//===--------------------------------------------------------------------===//
mlir::StringAttr createCommonLinkage() { return getStringAttr("common"); }
mlir::StringAttr createInternalLinkage() { return getStringAttr("internal"); }
mlir::StringAttr createLinkOnceLinkage() { return getStringAttr("linkonce"); }
mlir::StringAttr createLinkOnceODRLinkage() {
return getStringAttr("linkonce_odr");
}
mlir::StringAttr createWeakLinkage() { return getStringAttr("weak"); }
/// Get a function by name. If the function exists in the current module, it
/// is returned. Otherwise, a null FuncOp is returned.
mlir::func::FuncOp getNamedFunction(llvm::StringRef name) {
return getNamedFunction(getModule(), getMLIRSymbolTable(), name);
}
static mlir::func::FuncOp
getNamedFunction(mlir::ModuleOp module, const mlir::SymbolTable *symbolTable,
llvm::StringRef name);
/// Get a function by symbol name. The result will be null if there is no
/// function with the given symbol in the module.
mlir::func::FuncOp getNamedFunction(mlir::SymbolRefAttr symbol) {
return getNamedFunction(getModule(), getMLIRSymbolTable(), symbol);
}
static mlir::func::FuncOp
getNamedFunction(mlir::ModuleOp module, const mlir::SymbolTable *symbolTable,
mlir::SymbolRefAttr symbol);
fir::GlobalOp getNamedGlobal(llvm::StringRef name) {
return getNamedGlobal(getModule(), getMLIRSymbolTable(), name);
}
static fir::GlobalOp getNamedGlobal(mlir::ModuleOp module,
const mlir::SymbolTable *symbolTable,
llvm::StringRef name);
/// Lazy creation of fir.convert op.
mlir::Value createConvert(mlir::Location loc, mlir::Type toTy,
mlir::Value val);
/// Create a fir.store of \p val into \p addr. A lazy conversion
/// of \p val to the element type of \p addr is created if needed.
void createStoreWithConvert(mlir::Location loc, mlir::Value val,
mlir::Value addr);
/// Create a fir.load if \p val is a reference or pointer type. Return the
/// result of the load if it was created, otherwise return \p val
mlir::Value loadIfRef(mlir::Location loc, mlir::Value val);
/// Determine if the named function is already in the module. Return the
/// instance if found, otherwise add a new named function to the module.
mlir::func::FuncOp createFunction(mlir::Location loc, llvm::StringRef name,
mlir::FunctionType ty) {
return createFunction(loc, getModule(), name, ty, getMLIRSymbolTable());
}
static mlir::func::FuncOp createFunction(mlir::Location loc,
mlir::ModuleOp module,
llvm::StringRef name,
mlir::FunctionType ty,
mlir::SymbolTable *);
/// Cast the input value to IndexType.
mlir::Value convertToIndexType(mlir::Location loc, mlir::Value val) {
return createConvert(loc, getIndexType(), val);
}
/// Construct one of the two forms of shape op from an array box.
mlir::Value genShape(mlir::Location loc, const fir::AbstractArrayBox &arr);
mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift,
llvm::ArrayRef<mlir::Value> exts);
mlir::Value genShape(mlir::Location loc, llvm::ArrayRef<mlir::Value> exts);
mlir::Value genShift(mlir::Location loc, llvm::ArrayRef<mlir::Value> shift);
/// Create one of the shape ops given an extended value. For a boxed value,
/// this may create a `fir.shift` op.
mlir::Value createShape(mlir::Location loc, const fir::ExtendedValue &exv);
/// Create a slice op extended value. The value to be sliced, `exv`, must be
/// an array.
mlir::Value createSlice(mlir::Location loc, const fir::ExtendedValue &exv,
mlir::ValueRange triples, mlir::ValueRange path);
/// Create a boxed value (Fortran descriptor) to be passed to the runtime.
/// \p exv is an extended value holding a memory reference to the object that
/// must be boxed. This function will crash if provided something that is not
/// a memory reference type.
/// Array entities are boxed with a shape and possibly a shift. Character
/// entities are boxed with a LEN parameter.
mlir::Value createBox(mlir::Location loc, const fir::ExtendedValue &exv,
bool isPolymorphic = false, bool isAssumedType = false);
mlir::Value createBox(mlir::Location loc, mlir::Type boxType,
mlir::Value addr, mlir::Value shape, mlir::Value slice,
llvm::ArrayRef<mlir::Value> lengths, mlir::Value tdesc);
/// Create constant i1 with value 1. if \p b is true or 0. otherwise
mlir::Value createBool(mlir::Location loc, bool b) {
return createIntegerConstant(loc, getIntegerType(1), b ? 1 : 0);
}
//===--------------------------------------------------------------------===//
// If-Then-Else generation helper
//===--------------------------------------------------------------------===//
/// Helper class to create if-then-else in a structured way:
/// Usage: genIfOp().genThen([&](){...}).genElse([&](){...}).end();
/// Alternatively, getResults() can be used instead of end() to end the ifOp
/// and get the ifOp results.
class IfBuilder {
public:
IfBuilder(fir::IfOp ifOp, FirOpBuilder &builder)
: ifOp{ifOp}, builder{builder} {}
template <typename CC>
IfBuilder &genThen(CC func) {
builder.setInsertionPointToStart(&ifOp.getThenRegion().front());
func();
return *this;
}
template <typename CC>
IfBuilder &genElse(CC func) {
assert(!ifOp.getElseRegion().empty() && "must have else region");
builder.setInsertionPointToStart(&ifOp.getElseRegion().front());
func();
return *this;
}
void end() { builder.setInsertionPointAfter(ifOp); }
/// End the IfOp and return the results if any.
mlir::Operation::result_range getResults() {
end();
return ifOp.getResults();
}
fir::IfOp &getIfOp() { return ifOp; };
private:
fir::IfOp ifOp;
FirOpBuilder &builder;
};
/// Create an IfOp and returns an IfBuilder that can generate the else/then
/// bodies.
IfBuilder genIfOp(mlir::Location loc, mlir::TypeRange results,
mlir::Value cdt, bool withElseRegion) {
auto op = create<fir::IfOp>(loc, results, cdt, withElseRegion);
return IfBuilder(op, *this);
}
/// Create an IfOp with no "else" region, and no result values.
/// Usage: genIfThen(loc, cdt).genThen(lambda).end();
IfBuilder genIfThen(mlir::Location loc, mlir::Value cdt) {
auto op = create<fir::IfOp>(loc, std::nullopt, cdt, false);
return IfBuilder(op, *this);
}
/// Create an IfOp with an "else" region, and no result values.
/// Usage: genIfThenElse(loc, cdt).genThen(lambda).genElse(lambda).end();
IfBuilder genIfThenElse(mlir::Location loc, mlir::Value cdt) {
auto op = create<fir::IfOp>(loc, std::nullopt, cdt, true);
return IfBuilder(op, *this);
}
mlir::Value genNot(mlir::Location loc, mlir::Value boolean) {
return create<mlir::arith::CmpIOp>(loc, mlir::arith::CmpIPredicate::eq,
boolean, createBool(loc, false));
}
/// Generate code testing \p addr is not a null address.
mlir::Value genIsNotNullAddr(mlir::Location loc, mlir::Value addr);
/// Generate code testing \p addr is a null address.
mlir::Value genIsNullAddr(mlir::Location loc, mlir::Value addr);
/// Compute the extent of (lb:ub:step) as max((ub-lb+step)/step, 0). See
/// Fortran 2018 9.5.3.3.2 section for more details.
mlir::Value genExtentFromTriplet(mlir::Location loc, mlir::Value lb,
mlir::Value ub, mlir::Value step,
mlir::Type type);
/// Create an AbsentOp of \p argTy type and handle special cases, such as
/// Character Procedure Tuple arguments.
mlir::Value genAbsentOp(mlir::Location loc, mlir::Type argTy);
/// Set default FastMathFlags value for all operations
/// supporting mlir::arith::FastMathAttr that will be created
/// by this builder.
void setFastMathFlags(mlir::arith::FastMathFlags flags) {
fastMathFlags = flags;
}
/// Set default FastMathFlags value from the passed MathOptionsBase
/// config.
void setFastMathFlags(Fortran::common::MathOptionsBase options);
/// Get current FastMathFlags value.
mlir::arith::FastMathFlags getFastMathFlags() const { return fastMathFlags; }
/// Stringify FastMathFlags set in a way
/// that the string may be used for mangling a function name.
/// If FastMathFlags are set to 'none', then the result is an empty
/// string.
std::string getFastMathFlagsString() {
mlir::arith::FastMathFlags flags = getFastMathFlags();
if (flags == mlir::arith::FastMathFlags::none)
return {};
std::string fmfString{mlir::arith::stringifyFastMathFlags(flags)};
std::replace(fmfString.begin(), fmfString.end(), ',', '_');
return fmfString;
}
/// Dump the current function. (debug)
LLVM_DUMP_METHOD void dumpFunc();
/// FirOpBuilder hook for creating new operation.
void notifyOperationInserted(mlir::Operation *op,
mlir::OpBuilder::InsertPoint previous) override {
// We only care about newly created operations.
if (previous.isSet())
return;
setCommonAttributes(op);
}
/// Construct a data layout on demand and return it
mlir::DataLayout &getDataLayout();
private:
/// Set attributes (e.g. FastMathAttr) to \p op operation
/// based on the current attributes setting.
void setCommonAttributes(mlir::Operation *op) const;
KindMapping kindMap;
/// FastMathFlags that need to be set for operations that support
/// mlir::arith::FastMathAttr.
mlir::arith::FastMathFlags fastMathFlags{};
/// fir::GlobalOp and func::FuncOp symbol table to speed-up
/// lookups.
mlir::SymbolTable *symbolTable = nullptr;
/// DataLayout constructed on demand. Access via getDataLayout().
/// Stored via a unique_ptr rather than an optional so as not to bloat this
/// class when most instances won't ever need a data layout.
std::unique_ptr<mlir::DataLayout> dataLayout = nullptr;
};
} // namespace fir
namespace fir::factory {
//===----------------------------------------------------------------------===//
// ExtendedValue inquiry helpers
//===----------------------------------------------------------------------===//
/// Read or get character length from \p box that must contain a character
/// entity. If the length value is contained in the ExtendedValue, this will
/// not generate any code, otherwise this will generate a read of the fir.box
/// describing the entity.
mlir::Value readCharLen(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &box);
/// Read or get the extent in dimension \p dim of the array described by \p box.
mlir::Value readExtent(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &box, unsigned dim);
/// Read or get the lower bound in dimension \p dim of the array described by
/// \p box. If the lower bound is left default in the ExtendedValue,
/// \p defaultValue will be returned.
mlir::Value readLowerBound(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &box, unsigned dim,
mlir::Value defaultValue);
/// Read extents from \p box.
llvm::SmallVector<mlir::Value> readExtents(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::BoxValue &box);
/// Read a fir::BoxValue into an fir::UnboxValue, a fir::ArrayBoxValue or a
/// fir::CharArrayBoxValue. This should only be called if the fir::BoxValue is
/// known to be contiguous given the context (or if the resulting address will
/// not be used). If the value is polymorphic, its dynamic type will be lost.
/// This must not be used on unlimited polymorphic and assumed rank entities.
fir::ExtendedValue readBoxValue(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::BoxValue &box);
/// Get the lower bounds of \p exv. NB: returns an empty vector if the lower
/// bounds are all ones, which is the default in Fortran.
llvm::SmallVector<mlir::Value>
getNonDefaultLowerBounds(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &exv);
/// Return LEN parameters associated to \p exv that are not deferred (that are
/// available without having to read any fir.box values). Empty if \p exv has no
/// LEN parameters or if they are all deferred.
llvm::SmallVector<mlir::Value>
getNonDeferredLenParams(const fir::ExtendedValue &exv);
//===----------------------------------------------------------------------===//
// String literal helper helpers
//===----------------------------------------------------------------------===//
/// Create a !fir.char<1> string literal global and returns a fir::CharBoxValue
/// with its address and length.
fir::ExtendedValue createStringLiteral(fir::FirOpBuilder &, mlir::Location,
llvm::StringRef string);
/// Unique a compiler generated identifier. A short prefix should be provided
/// to hint at the origin of the identifier.
std::string uniqueCGIdent(llvm::StringRef prefix, llvm::StringRef name);
/// Lowers the extents from the sequence type to Values.
/// Any unknown extents are lowered to undefined values.
llvm::SmallVector<mlir::Value> createExtents(fir::FirOpBuilder &builder,
mlir::Location loc,
fir::SequenceType seqTy);
//===--------------------------------------------------------------------===//
// Location helpers
//===--------------------------------------------------------------------===//
/// Generate a string literal containing the file name and return its address
mlir::Value locationToFilename(fir::FirOpBuilder &, mlir::Location);
/// Generate a constant of the given type with the location line number
mlir::Value locationToLineNo(fir::FirOpBuilder &, mlir::Location, mlir::Type);
//===--------------------------------------------------------------------===//
// ExtendedValue helpers
//===--------------------------------------------------------------------===//
/// Return the extended value for a component of a derived type instance given
/// the address of the component.
fir::ExtendedValue componentToExtendedValue(fir::FirOpBuilder &builder,
mlir::Location loc,
mlir::Value component);
/// Given the address of an array element and the ExtendedValue describing the
/// array, returns the ExtendedValue describing the array element. The purpose
/// is to propagate the LEN parameters of the array to the element. This can be
/// used for elements of `array` or `array(i:j:k)`. If \p element belongs to an
/// array section `array%x` whose base is \p array,
/// arraySectionElementToExtendedValue must be used instead.
fir::ExtendedValue arrayElementToExtendedValue(fir::FirOpBuilder &builder,
mlir::Location loc,
const fir::ExtendedValue &array,
mlir::Value element);
/// Build the ExtendedValue for \p element that is an element of an array or
/// array section with \p array base (`array` or `array(i:j:k)%x%y`).
/// If it is an array section, \p slice must be provided and be a fir::SliceOp
/// that describes the section.
fir::ExtendedValue arraySectionElementToExtendedValue(
fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &array, mlir::Value element, mlir::Value slice);
/// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalars. The
/// assignment follows Fortran intrinsic assignment semantic (10.2.1.3).
void genScalarAssignment(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &lhs,
const fir::ExtendedValue &rhs,
bool needFinalization = false,
bool isTemporaryLHS = false);
/// Assign \p rhs to \p lhs. Both \p rhs and \p lhs must be scalar derived
/// types. The assignment follows Fortran intrinsic assignment semantic for
/// derived types (10.2.1.3 point 13).
void genRecordAssignment(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &lhs,
const fir::ExtendedValue &rhs,
bool needFinalization = false,
bool isTemporaryLHS = false);
/// Builds and returns the type of a ragged array header used to cache mask
/// evaluations. RaggedArrayHeader is defined in
/// flang/include/flang/Runtime/ragged.h.
mlir::TupleType getRaggedArrayHeaderType(fir::FirOpBuilder &builder);
/// Generate the, possibly dynamic, LEN of a CHARACTER. \p arrLoad determines
/// the base array. After applying \p path, the result must be a reference to a
/// `!fir.char` type object. \p substring must have 0, 1, or 2 members. The
/// first member is the starting offset. The second is the ending offset.
mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc,
fir::ArrayLoadOp arrLoad,
llvm::ArrayRef<mlir::Value> path,
llvm::ArrayRef<mlir::Value> substring);
mlir::Value genLenOfCharacter(fir::FirOpBuilder &builder, mlir::Location loc,
fir::SequenceType seqTy, mlir::Value memref,
llvm::ArrayRef<mlir::Value> typeParams,
llvm::ArrayRef<mlir::Value> path,
llvm::ArrayRef<mlir::Value> substring);
/// Create the zero value of a given the numerical or logical \p type (`false`
/// for logical types).
mlir::Value createZeroValue(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Type type);
/// Get the integer constants of triplet and compute the extent.
std::optional<std::int64_t> getExtentFromTriplet(mlir::Value lb, mlir::Value ub,
mlir::Value stride);
/// Generate max(\p value, 0) where \p value is a scalar integer.
mlir::Value genMaxWithZero(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value value);
/// The type(C_PTR/C_FUNPTR) is defined as the derived type with only one
/// component of integer 64, and the component is the C address. Get the C
/// address.
mlir::Value genCPtrOrCFunptrAddr(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Value cPtr, mlir::Type ty);
/// Get the C address value.
mlir::Value genCPtrOrCFunptrValue(fir::FirOpBuilder &builder,
mlir::Location loc, mlir::Value cPtr);
/// Create a fir.box from a fir::ExtendedValue and wrap it in a fir::BoxValue
/// to keep all the lower bound and explicit parameter information.
fir::BoxValue createBoxValue(fir::FirOpBuilder &builder, mlir::Location loc,
const fir::ExtendedValue &exv);
/// Generate Null BoxProc for procedure pointer null initialization.
mlir::Value createNullBoxProc(fir::FirOpBuilder &builder, mlir::Location loc,
mlir::Type boxType);
/// Convert a value to a new type. Return the value directly if it has the right
/// type.
mlir::Value createConvert(mlir::OpBuilder &, mlir::Location, mlir::Type,
mlir::Value);
/// Set internal linkage attribute on a function.
void setInternalLinkage(mlir::func::FuncOp);
llvm::SmallVector<mlir::Value>
elideExtentsAlreadyInType(mlir::Type type, mlir::ValueRange shape);
llvm::SmallVector<mlir::Value>
elideLengthsAlreadyInType(mlir::Type type, mlir::ValueRange lenParams);
/// Get the address space which should be used for allocas
uint64_t getAllocaAddressSpace(mlir::DataLayout *dataLayout);
} // namespace fir::factory
#endif // FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H