Skip to content

Commit 7efd613

Browse files
authored
[flang][cuda] Get device address in fir.declare (#118591)
Add pattern that update fir.declare memref when it comes from a device global and is not a descriptor. In that case, we recover the device address that needs to be used in ops like `fir.array_coor` and so on.
1 parent e6bd00c commit 7efd613

File tree

4 files changed

+147
-73
lines changed

4 files changed

+147
-73
lines changed

flang/include/flang/Optimizer/Transforms/CUFOpConversion.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,16 @@ class SymbolTable;
2323

2424
namespace cuf {
2525

26+
/// Patterns that convert CUF operations to runtime calls.
2627
void populateCUFToFIRConversionPatterns(const fir::LLVMTypeConverter &converter,
2728
mlir::DataLayout &dl,
2829
const mlir::SymbolTable &symtab,
2930
mlir::RewritePatternSet &patterns);
3031

32+
/// Patterns that updates fir operations in presence of CUF.
33+
void populateFIRCUFConversionPatterns(const mlir::SymbolTable &symtab,
34+
mlir::RewritePatternSet &patterns);
35+
3136
} // namespace cuf
3237

3338
#endif // FORTRAN_OPTIMIZER_TRANSFORMS_CUFOPCONVERSION_H_

flang/lib/Optimizer/Transforms/CUFOpConversion.cpp

Lines changed: 90 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,15 @@ static bool hasDoubleDescriptors(OpTy op) {
8181
return false;
8282
}
8383

84+
bool isDeviceGlobal(fir::GlobalOp op) {
85+
auto attr = op.getDataAttr();
86+
if (attr && (*attr == cuf::DataAttribute::Device ||
87+
*attr == cuf::DataAttribute::Managed ||
88+
*attr == cuf::DataAttribute::Constant))
89+
return true;
90+
return false;
91+
}
92+
8493
static mlir::Value createConvertOp(mlir::PatternRewriter &rewriter,
8594
mlir::Location loc, mlir::Type toTy,
8695
mlir::Value val) {
@@ -89,62 +98,6 @@ static mlir::Value createConvertOp(mlir::PatternRewriter &rewriter,
8998
return val;
9099
}
91100

92-
mlir::Value getDeviceAddress(mlir::PatternRewriter &rewriter,
93-
mlir::OpOperand &operand,
94-
const mlir::SymbolTable &symtab) {
95-
mlir::Value v = operand.get();
96-
auto declareOp = v.getDefiningOp<fir::DeclareOp>();
97-
if (!declareOp)
98-
return v;
99-
100-
auto addrOfOp = declareOp.getMemref().getDefiningOp<fir::AddrOfOp>();
101-
if (!addrOfOp)
102-
return v;
103-
104-
auto globalOp = symtab.lookup<fir::GlobalOp>(
105-
addrOfOp.getSymbol().getRootReference().getValue());
106-
107-
if (!globalOp)
108-
return v;
109-
110-
bool isDevGlobal{false};
111-
auto attr = globalOp.getDataAttrAttr();
112-
if (attr) {
113-
switch (attr.getValue()) {
114-
case cuf::DataAttribute::Device:
115-
case cuf::DataAttribute::Managed:
116-
case cuf::DataAttribute::Constant:
117-
isDevGlobal = true;
118-
break;
119-
default:
120-
break;
121-
}
122-
}
123-
if (!isDevGlobal)
124-
return v;
125-
mlir::OpBuilder::InsertionGuard guard(rewriter);
126-
rewriter.setInsertionPoint(operand.getOwner());
127-
auto loc = declareOp.getLoc();
128-
auto mod = declareOp->getParentOfType<mlir::ModuleOp>();
129-
fir::FirOpBuilder builder(rewriter, mod);
130-
131-
mlir::func::FuncOp callee =
132-
fir::runtime::getRuntimeFunc<mkRTKey(CUFGetDeviceAddress)>(loc, builder);
133-
auto fTy = callee.getFunctionType();
134-
auto toTy = fTy.getInput(0);
135-
mlir::Value inputArg =
136-
createConvertOp(rewriter, loc, toTy, declareOp.getResult());
137-
mlir::Value sourceFile = fir::factory::locationToFilename(builder, loc);
138-
mlir::Value sourceLine =
139-
fir::factory::locationToLineNo(builder, loc, fTy.getInput(2));
140-
llvm::SmallVector<mlir::Value> args{fir::runtime::createArguments(
141-
builder, loc, fTy, inputArg, sourceFile, sourceLine)};
142-
auto call = rewriter.create<fir::CallOp>(loc, callee, args);
143-
mlir::Value cast = createConvertOp(
144-
rewriter, loc, declareOp.getMemref().getType(), call->getResult(0));
145-
return cast;
146-
}
147-
148101
template <typename OpTy>
149102
static mlir::LogicalResult convertOpToCall(OpTy op,
150103
mlir::PatternRewriter &rewriter,
@@ -422,6 +375,54 @@ struct CUFAllocOpConversion : public mlir::OpRewritePattern<cuf::AllocOp> {
422375
const fir::LLVMTypeConverter *typeConverter;
423376
};
424377

378+
struct DeclareOpConversion : public mlir::OpRewritePattern<fir::DeclareOp> {
379+
using OpRewritePattern::OpRewritePattern;
380+
381+
DeclareOpConversion(mlir::MLIRContext *context,
382+
const mlir::SymbolTable &symtab)
383+
: OpRewritePattern(context), symTab{symtab} {}
384+
385+
mlir::LogicalResult
386+
matchAndRewrite(fir::DeclareOp op,
387+
mlir::PatternRewriter &rewriter) const override {
388+
if (auto addrOfOp = op.getMemref().getDefiningOp<fir::AddrOfOp>()) {
389+
if (auto global = symTab.lookup<fir::GlobalOp>(
390+
addrOfOp.getSymbol().getRootReference().getValue())) {
391+
if (isDeviceGlobal(global)) {
392+
rewriter.setInsertionPointAfter(addrOfOp);
393+
auto mod = op->getParentOfType<mlir::ModuleOp>();
394+
fir::FirOpBuilder builder(rewriter, mod);
395+
mlir::Location loc = op.getLoc();
396+
mlir::func::FuncOp callee =
397+
fir::runtime::getRuntimeFunc<mkRTKey(CUFGetDeviceAddress)>(
398+
loc, builder);
399+
auto fTy = callee.getFunctionType();
400+
mlir::Type toTy = fTy.getInput(0);
401+
mlir::Value inputArg =
402+
createConvertOp(rewriter, loc, toTy, addrOfOp.getResult());
403+
mlir::Value sourceFile =
404+
fir::factory::locationToFilename(builder, loc);
405+
mlir::Value sourceLine =
406+
fir::factory::locationToLineNo(builder, loc, fTy.getInput(2));
407+
llvm::SmallVector<mlir::Value> args{fir::runtime::createArguments(
408+
builder, loc, fTy, inputArg, sourceFile, sourceLine)};
409+
auto call = rewriter.create<fir::CallOp>(loc, callee, args);
410+
mlir::Value cast = createConvertOp(
411+
rewriter, loc, op.getMemref().getType(), call->getResult(0));
412+
rewriter.startOpModification(op);
413+
op.getMemrefMutable().assign(cast);
414+
rewriter.finalizeOpModification(op);
415+
return success();
416+
}
417+
}
418+
}
419+
return failure();
420+
}
421+
422+
private:
423+
const mlir::SymbolTable &symTab;
424+
};
425+
425426
struct CUFFreeOpConversion : public mlir::OpRewritePattern<cuf::FreeOp> {
426427
using OpRewritePattern::OpRewritePattern;
427428

@@ -511,7 +512,7 @@ static mlir::Value emboxSrc(mlir::PatternRewriter &rewriter,
511512
builder.create<fir::StoreOp>(loc, src, alloc);
512513
addr = alloc;
513514
} else {
514-
addr = getDeviceAddress(rewriter, op.getSrcMutable(), symtab);
515+
addr = op.getSrc();
515516
}
516517
llvm::SmallVector<mlir::Value> lenParams;
517518
mlir::Type boxTy = fir::BoxType::get(srcTy);
@@ -531,7 +532,7 @@ static mlir::Value emboxDst(mlir::PatternRewriter &rewriter,
531532
mlir::Location loc = op.getLoc();
532533
fir::FirOpBuilder builder(rewriter, mod);
533534
mlir::Type dstTy = fir::unwrapRefType(op.getDst().getType());
534-
mlir::Value dstAddr = getDeviceAddress(rewriter, op.getDstMutable(), symtab);
535+
mlir::Value dstAddr = op.getDst();
535536
mlir::Type dstBoxTy = fir::BoxType::get(dstTy);
536537
llvm::SmallVector<mlir::Value> lenParams;
537538
mlir::Value dstBox =
@@ -652,8 +653,8 @@ struct CUFDataTransferOpConversion
652653
mlir::Value sourceLine =
653654
fir::factory::locationToLineNo(builder, loc, fTy.getInput(5));
654655

655-
mlir::Value dst = getDeviceAddress(rewriter, op.getDstMutable(), symtab);
656-
mlir::Value src = getDeviceAddress(rewriter, op.getSrcMutable(), symtab);
656+
mlir::Value dst = op.getDst();
657+
mlir::Value src = op.getSrc();
657658
// Materialize the src if constant.
658659
if (matchPattern(src.getDefiningOp(), mlir::m_Constant())) {
659660
mlir::Value temp = builder.createTemporary(loc, srcTy);
@@ -823,6 +824,30 @@ class CUFOpConversion : public fir::impl::CUFOpConversionBase<CUFOpConversion> {
823824
"error in CUF op conversion\n");
824825
signalPassFailure();
825826
}
827+
828+
target.addDynamicallyLegalOp<fir::DeclareOp>([&](fir::DeclareOp op) {
829+
if (inDeviceContext(op))
830+
return true;
831+
if (auto addrOfOp = op.getMemref().getDefiningOp<fir::AddrOfOp>()) {
832+
if (auto global = symtab.lookup<fir::GlobalOp>(
833+
addrOfOp.getSymbol().getRootReference().getValue())) {
834+
if (mlir::isa<fir::BaseBoxType>(fir::unwrapRefType(global.getType())))
835+
return true;
836+
if (isDeviceGlobal(global))
837+
return false;
838+
}
839+
}
840+
return true;
841+
});
842+
843+
patterns.clear();
844+
cuf::populateFIRCUFConversionPatterns(symtab, patterns);
845+
if (mlir::failed(mlir::applyPartialConversion(getOperation(), target,
846+
std::move(patterns)))) {
847+
mlir::emitError(mlir::UnknownLoc::get(ctx),
848+
"error in CUF op conversion\n");
849+
signalPassFailure();
850+
}
826851
}
827852
};
828853
} // namespace
@@ -837,3 +862,8 @@ void cuf::populateCUFToFIRConversionPatterns(
837862
&dl, &converter);
838863
patterns.insert<CUFLaunchOpConversion>(patterns.getContext(), symtab);
839864
}
865+
866+
void cuf::populateFIRCUFConversionPatterns(const mlir::SymbolTable &symtab,
867+
mlir::RewritePatternSet &patterns) {
868+
patterns.insert<DeclareOpConversion>(patterns.getContext(), symtab);
869+
}

flang/test/Fir/CUDA/cuda-data-transfer.fir

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,12 @@ func.func @_QPsub8() attributes {fir.bindc_name = "t"} {
199199
// CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<5xi32>
200200
// CHECK: %[[LOCAL:.*]] = fir.declare %[[ALLOCA]]
201201
// CHECK: %[[GBL:.*]] = fir.address_of(@_QMmtestsEn) : !fir.ref<!fir.array<5xi32>>
202-
// CHECK: %[[DECL:.*]] = fir.declare %[[GBL]]
203-
// CHECK: %[[HOST:.*]] = fir.convert %[[DECL]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
204-
// CHECK: %[[SRC:.*]] = fir.call @_FortranACUFGetDeviceAddress(%[[HOST]], %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> !fir.llvm_ptr<i8>
205-
// CHECK: %[[SRC_CONV:.*]] = fir.convert %[[SRC]] : (!fir.llvm_ptr<i8>) -> !fir.ref<!fir.array<5xi32>>
202+
// CHECK: %[[GBL_CONV:.*]] = fir.convert %[[GBL]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
203+
// CHECK: %[[ADDR:.*]] = fir.call @_FortranACUFGetDeviceAddress(%[[GBL_CONV]], %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> !fir.llvm_ptr<i8>
204+
// CHECK: %[[ADDR_CONV:.*]] = fir.convert %[[ADDR]] : (!fir.llvm_ptr<i8>) -> !fir.ref<!fir.array<5xi32>>
205+
// CHECK: %[[DECL:.*]] = fir.declare %[[ADDR_CONV]]
206206
// CHECK: %[[DST:.*]] = fir.convert %[[LOCAL]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
207-
// CHECK: %[[SRC:.*]] = fir.convert %[[SRC_CONV]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
207+
// CHECK: %[[SRC:.*]] = fir.convert %[[DECL]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
208208
// CHECK: fir.call @_FortranACUFDataTransferPtrPtr(%[[DST]], %[[SRC]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.llvm_ptr<i8>, i64, i32, !fir.ref<i8>, i32) -> none
209209

210210

@@ -223,11 +223,11 @@ func.func @_QPsub9() {
223223
// CHECK: %[[ALLOCA:.*]] = fir.alloca !fir.array<5xi32>
224224
// CHECK: %[[LOCAL:.*]] = fir.declare %[[ALLOCA]]
225225
// CHECK: %[[GBL:.*]] = fir.address_of(@_QMmtestsEn) : !fir.ref<!fir.array<5xi32>>
226-
// CHECK: %[[DECL:.*]] = fir.declare %[[GBL]]
227-
// CHECK: %[[HOST:.*]] = fir.convert %[[DECL]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
228-
// CHECK: %[[DST:.*]] = fir.call @_FortranACUFGetDeviceAddress(%[[HOST]], %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> !fir.llvm_ptr<i8>
229-
// CHECK: %[[DST_CONV:.*]] = fir.convert %[[DST]] : (!fir.llvm_ptr<i8>) -> !fir.ref<!fir.array<5xi32>>
230-
// CHECK: %[[DST:.*]] = fir.convert %[[DST_CONV]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
226+
// CHECK: %[[GBL_CONV:.*]] = fir.convert %[[GBL]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
227+
// CHECK: %[[ADDR:.*]] = fir.call @_FortranACUFGetDeviceAddress(%[[GBL_CONV]], %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> !fir.llvm_ptr<i8>
228+
// CHECK: %[[ADDR_CONV:.*]] = fir.convert %[[ADDR]] : (!fir.llvm_ptr<i8>) -> !fir.ref<!fir.array<5xi32>>
229+
// CHECK: %[[DECL:.*]] = fir.declare %[[ADDR_CONV]]
230+
// CHECK: %[[DST:.*]] = fir.convert %[[DECL]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
231231
// CHECK: %[[SRC:.*]] = fir.convert %[[LOCAL]] : (!fir.ref<!fir.array<5xi32>>) -> !fir.llvm_ptr<i8>
232232
// CHECK: fir.call @_FortranACUFDataTransferPtrPtr(%[[DST]], %[[SRC]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.llvm_ptr<i8>, i64, i32, !fir.ref<i8>, i32) -> none
233233

@@ -380,9 +380,12 @@ func.func @_QPdevice_addr_conv() {
380380
}
381381

382382
// CHECK-LABEL: func.func @_QPdevice_addr_conv()
383-
// CHECK: %[[DEV_ADDR:.*]] = fir.call @_FortranACUFGetDeviceAddress(%{{.*}}, %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> !fir.llvm_ptr<i8>
384-
// CHECK: %[[DEV_ADDR_CONV:.*]] = fir.convert %[[DEV_ADDR]] : (!fir.llvm_ptr<i8>) -> !fir.ref<!fir.array<4xf32>>
385-
// CHECK: fir.embox %[[DEV_ADDR_CONV]](%{{.*}}) : (!fir.ref<!fir.array<4xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<4xf32>>
383+
// CHECK: %[[GBL:.*]] = fir.address_of(@_QMmod1Ea_dev) : !fir.ref<!fir.array<4xf32>>
384+
// CHECK: %[[GBL_CONV:.*]] = fir.convert %[[GBL]] : (!fir.ref<!fir.array<4xf32>>) -> !fir.llvm_ptr<i8>
385+
// CHECK: %[[ADDR:.*]] = fir.call @_FortranACUFGetDeviceAddress(%[[GBL_CONV]], %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> !fir.llvm_ptr<i8>
386+
// CHECK: %[[ADDR_CONV:.*]] = fir.convert %[[ADDR]] : (!fir.llvm_ptr<i8>) -> !fir.ref<!fir.array<4xf32>>
387+
// CHECK: %[[DECL:.*]] = fir.declare %[[ADDR_CONV]](%{{.*}}) {data_attr = #cuf.cuda<device>, uniq_name = "_QMmod1Ea_dev"} : (!fir.ref<!fir.array<4xf32>>, !fir.shape<1>) -> !fir.ref<!fir.array<4xf32>>
388+
// CHECK: fir.embox %[[DECL]](%{{.*}}) : (!fir.ref<!fir.array<4xf32>>, !fir.shape<1>) -> !fir.box<!fir.array<4xf32>>
386389
// CHECK: fir.call @_FortranACUFDataTransferCstDesc
387390

388391
func.func @_QQchar_transfer() attributes {fir.bindc_name = "char_transfer"} {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// RUN: fir-opt --cuf-convert %s | FileCheck %s
2+
3+
module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<f80, dense<128> : vector<2xi64>>, #dlti.dl_entry<i128, dense<128> : vector<2xi64>>, #dlti.dl_entry<i64, dense<64> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi64>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi64>>, #dlti.dl_entry<f128, dense<128> : vector<2xi64>>, #dlti.dl_entry<f64, dense<64> : vector<2xi64>>, #dlti.dl_entry<f16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i32, dense<32> : vector<2xi64>>, #dlti.dl_entry<i16, dense<16> : vector<2xi64>>, #dlti.dl_entry<i8, dense<8> : vector<2xi64>>, #dlti.dl_entry<i1, dense<8> : vector<2xi64>>, #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi64>>, #dlti.dl_entry<"dlti.endianness", "little">, #dlti.dl_entry<"dlti.stack_alignment", 128 : i64>>} {
4+
fir.global @_QMmod1Eadev {data_attr = #cuf.cuda<device>} : !fir.array<10xi32> {
5+
%0 = fir.zero_bits !fir.array<10xi32>
6+
fir.has_value %0 : !fir.array<10xi32>
7+
}
8+
func.func @_QQmain() attributes {fir.bindc_name = "test"} {
9+
%c14_i32 = arith.constant 14 : i32
10+
%c6_i32 = arith.constant 6 : i32
11+
%c4 = arith.constant 4 : index
12+
%c1_i32 = arith.constant 1 : i32
13+
%c0_i32 = arith.constant 0 : i32
14+
%c10 = arith.constant 10 : index
15+
%1 = fir.shape %c10 : (index) -> !fir.shape<1>
16+
%3 = fir.address_of(@_QMmod1Eadev) : !fir.ref<!fir.array<10xi32>>
17+
%4 = fir.declare %3(%1) {data_attr = #cuf.cuda<device>, uniq_name = "_QMmod1Eadev"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>>
18+
%5 = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFEi"}
19+
%6 = fir.declare %5 {uniq_name = "_QFEi"} : (!fir.ref<i32>) -> !fir.ref<i32>
20+
fir.store %c0_i32 to %6 : !fir.ref<i32>
21+
%7 = fir.array_coor %4(%1) %c4 : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
22+
cuf.data_transfer %c1_i32 to %7 {transfer_kind = #cuf.cuda_transfer<host_device>} : i32, !fir.ref<i32>
23+
return
24+
}
25+
26+
}
27+
28+
// CHECK-LABEL: func.func @_QQmain()
29+
// CHECK: %[[ADDR:.*]] = fir.address_of(@_QMmod1Eadev) : !fir.ref<!fir.array<10xi32>>
30+
// CHECK: %[[ADDRPTR:.*]] = fir.convert %[[ADDR]] : (!fir.ref<!fir.array<10xi32>>) -> !fir.llvm_ptr<i8>
31+
// CHECK: %[[DEVICE_ADDR:.*]] = fir.call @_FortranACUFGetDeviceAddress(%[[ADDRPTR]], %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.ref<i8>, i32) -> !fir.llvm_ptr<i8>
32+
// CHECK: %[[DEVICE_ADDR_CONV:.*]] = fir.convert %[[DEVICE_ADDR]] : (!fir.llvm_ptr<i8>) -> !fir.ref<!fir.array<10xi32>>
33+
// CHECK: %[[DECL:.*]] = fir.declare %[[DEVICE_ADDR_CONV]](%{{.*}}) {data_attr = #cuf.cuda<device>, uniq_name = "_QMmod1Eadev"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.ref<!fir.array<10xi32>>
34+
// CHECK: %[[ARRAY_COOR:.*]] = fir.array_coor %[[DECL]](%{{.*}}) %c4{{.*}} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, index) -> !fir.ref<i32>
35+
// CHECK: %[[ARRAY_COOR_PTR:.*]] = fir.convert %[[ARRAY_COOR]] : (!fir.ref<i32>) -> !fir.llvm_ptr<i8>
36+
// CHECK: fir.call @_FortranACUFDataTransferPtrPtr(%[[ARRAY_COOR_PTR]], %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}, %{{.*}}) : (!fir.llvm_ptr<i8>, !fir.llvm_ptr<i8>, i64, i32, !fir.ref<i8>, i32) -> none

0 commit comments

Comments
 (0)