Skip to content

Commit 423fe88

Browse files
Handle allocatables and add lit tests
1 parent 17ecdba commit 423fe88

File tree

4 files changed

+574
-8
lines changed

4 files changed

+574
-8
lines changed

mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp

Lines changed: 161 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include <optional>
4242
#include <utility>
4343

44+
#define DEBUG_TYPE "openmp-to-llvm-ir-translation"
4445
using namespace mlir;
4546

4647
namespace {
@@ -3316,7 +3317,56 @@ createDeviceArgumentAccessor(MapInfoData &mapData, llvm::Argument &arg,
33163317

33173318
return builder.saveIP();
33183319
}
3320+
static bool privatizerNeedsMap(omp::PrivateClauseOp &privatizer) {
3321+
Region &allocRegion = privatizer.getAllocRegion();
3322+
Value blockArg0 = allocRegion.getArgument(0);
3323+
return !blockArg0.use_empty();
3324+
}
3325+
static llvm::Value *
3326+
findHostAssociatedValue(Value privateVar, omp::TargetOp targetOp,
3327+
llvm::DenseMap<Value, int> &mappedPrivateVars,
3328+
llvm::IRBuilderBase &builder,
3329+
LLVM::ModuleTranslation &moduleTranslation) {
3330+
if (mappedPrivateVars.contains(privateVar)) {
3331+
int blockArgIndex = mappedPrivateVars[privateVar];
3332+
Value blockArg = targetOp.getRegion().getArgument(blockArgIndex);
3333+
mlir::Type privVarType = privateVar.getType();
3334+
mlir::Type blockArgType = blockArg.getType();
3335+
assert(isa<LLVM::LLVMPointerType>(blockArgType) &&
3336+
"A block argument corresponding to a mapped var should have "
3337+
"!llvm.ptr type");
3338+
3339+
LLVM_DEBUG(llvm::dbgs() << "privVarType = ");
3340+
LLVM_DEBUG(privVarType.dump());
3341+
LLVM_DEBUG(llvm::dbgs() << "\n");
3342+
LLVM_DEBUG(llvm::dbgs() << "blockArgType = ");
3343+
LLVM_DEBUG(blockArg.getType().dump());
3344+
LLVM_DEBUG(llvm::dbgs() << "\n");
3345+
3346+
if (privVarType == blockArg.getType()) {
3347+
llvm::Value *v = moduleTranslation.lookupValue(blockArg);
3348+
LLVM_DEBUG(llvm::dbgs() << "Host Associated Value : ");
3349+
LLVM_DEBUG(v->dump());
3350+
return v;
3351+
}
33193352

3353+
if (!isa<LLVM::LLVMPointerType>(privVarType)) {
3354+
// This typically happens when the privatized type is lowered from
3355+
// boxchar<KIND> and gets lowered to !llvm.struct<(ptr, i64)>. That is the
3356+
// struct/pair is passed by value. But, mapped values are passed only as
3357+
// pointers, so before we privatize, we must load the pointer.
3358+
llvm::Value *load =
3359+
builder.CreateLoad(moduleTranslation.convertType(privVarType),
3360+
moduleTranslation.lookupValue(blockArg));
3361+
LLVM_DEBUG(llvm::dbgs() << "Host Associated Value : ");
3362+
LLVM_DEBUG(load->dump());
3363+
return load;
3364+
}
3365+
}
3366+
LLVM_DEBUG(llvm::dbgs() << "Host Associated Value : ");
3367+
LLVM_DEBUG(moduleTranslation.lookupValue(privateVar)->dump());
3368+
return moduleTranslation.lookupValue(privateVar);
3369+
}
33203370
static LogicalResult
33213371
convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
33223372
LLVM::ModuleTranslation &moduleTranslation) {
@@ -3329,6 +3379,19 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
33293379
auto parentFn = opInst.getParentOfType<LLVM::LLVMFuncOp>();
33303380
auto targetOp = cast<omp::TargetOp>(opInst);
33313381
auto &targetRegion = targetOp.getRegion();
3382+
// Holds the private vars that have been mapped along with
3383+
// the block argument that corresponds to the MapInfoOp
3384+
// corresponding to the private var in question.
3385+
// So, for instance
3386+
//
3387+
// %10 = omp.map.info var_ptr(%6#0 : !fir.ref<!fir.box<!fir.heap<i32>>>, ..)
3388+
// omp.target map_entries(%10 -> %arg0) private(@box.privatizer %6#0-> %arg1)
3389+
//
3390+
// Then, %10 has been created so that the descriptor can be used by the
3391+
// privatizer
3392+
// @box.privatizer on the device side. Here we'd record {%6#0, 0} in the
3393+
// mappedPrivateVars map.
3394+
llvm::DenseMap<Value, int> mappedPrivateVars;
33323395
DataLayout dl = DataLayout(opInst.getParentOfType<ModuleOp>());
33333396
SmallVector<Value> mapVars = targetOp.getMapVars();
33343397
ArrayRef<BlockArgument> mapBlockArgs =
@@ -3340,6 +3403,66 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
33403403
bool isOffloadEntry =
33413404
isTargetDevice || !ompBuilder->Config.TargetTriples.empty();
33423405

3406+
// For some private variables, the MapsForPrivatizedVariablesPass
3407+
// creates MapInfoOp instances. Go through the private variables and
3408+
// the mapped variables so that during codegeneration we are able
3409+
// to quickly look up the corresponding map variable, if any for each
3410+
// private variable.
3411+
if (!targetOp.getPrivateVars().empty() && !targetOp.getMapVars().empty()) {
3412+
auto argIface = llvm::cast<omp::BlockArgOpenMPOpInterface>(*targetOp);
3413+
unsigned lastMapBlockArgsIdx =
3414+
argIface.getMapBlockArgsStart() + argIface.numMapBlockArgs() - 1;
3415+
OperandRange privateVars = targetOp.getPrivateVars();
3416+
std::optional<ArrayAttr> privateSyms = targetOp.getPrivateSyms();
3417+
auto reverseIt = mapVars.rbegin();
3418+
LLVM_DEBUG(llvm::dbgs() << "****Private Vars*******\n");
3419+
for (auto [privVar, privSym] :
3420+
llvm::reverse(llvm::zip_equal(privateVars, *privateSyms))) {
3421+
LLVM_DEBUG(llvm::dbgs() << "-- {\n");
3422+
LLVM_DEBUG(privVar.dump());
3423+
LLVM_DEBUG(llvm::dbgs() << "Type:-> ");
3424+
LLVM_DEBUG(privVar.getType().dump());
3425+
SymbolRefAttr privatizerName = llvm::cast<SymbolRefAttr>(privSym);
3426+
LLVM_DEBUG(llvm::dbgs() << "Privatizer: " << privatizerName << "\n}");
3427+
3428+
omp::PrivateClauseOp privatizer =
3429+
SymbolTable::lookupNearestSymbolFrom<omp::PrivateClauseOp>(
3430+
targetOp, privatizerName);
3431+
if (!privatizerNeedsMap(privatizer)) {
3432+
LLVM_DEBUG(llvm::dbgs() << " - DOES NOT need map\n");
3433+
continue;
3434+
}
3435+
LLVM_DEBUG(llvm::dbgs() << " - NEEDS map");
3436+
LLVM_DEBUG(llvm::dbgs() << " -> Mapped Arg : -> ");
3437+
LLVM_DEBUG((*reverseIt).dump());
3438+
LLVM_DEBUG(llvm::dbgs() << " -> Block Arg: -> ");
3439+
LLVM_DEBUG(targetOp.getRegion().getArgument(lastMapBlockArgsIdx).dump());
3440+
LLVM_DEBUG(llvm::dbgs() << "\n");
3441+
3442+
// The MapInfoOp defining the map var isn't really needed later.
3443+
// We'll do some sanity checks on it right now.
3444+
omp::MapInfoOp mapInfoOp =
3445+
llvm::cast<omp::MapInfoOp>((*reverseIt).getDefiningOp());
3446+
Type varType = mapInfoOp.getVarType();
3447+
LLVM_DEBUG(llvm::dbgs() << "mapInfoOp.getVarType() = ");
3448+
LLVM_DEBUG(varType.dump());
3449+
LLVM_DEBUG(llvm::dbgs() << "\n");
3450+
3451+
if (!isa<LLVM::LLVMPointerType>(privVar.getType()))
3452+
assert(
3453+
varType == privVar.getType() &&
3454+
"Type of private var doesn't match the type of the mapped value");
3455+
mappedPrivateVars.insert({privVar, lastMapBlockArgsIdx});
3456+
lastMapBlockArgsIdx--;
3457+
reverseIt++;
3458+
}
3459+
}
3460+
for (auto [privVar, blockArgIdx] : mappedPrivateVars) {
3461+
LLVM_DEBUG(llvm::dbgs() << "*****Private->MappedVars****\n");
3462+
LLVM_DEBUG(privVar.dump());
3463+
LLVM_DEBUG(llvm::dbgs() << "->\n");
3464+
LLVM_DEBUG(targetRegion.getArgument(blockArgIdx).dump());
3465+
}
33433466
LogicalResult bodyGenStatus = success();
33443467
using InsertPointTy = llvm::OpenMPIRBuilder::InsertPointTy;
33453468
auto bodyCB = [&](InsertPointTy allocaIP,
@@ -3365,11 +3488,21 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
33653488
auto mapInfoOp = cast<omp::MapInfoOp>(mapOp.getDefiningOp());
33663489
llvm::Value *mapOpValue =
33673490
moduleTranslation.lookupValue(mapInfoOp.getVarPtr());
3491+
LLVM_DEBUG(llvm::dbgs()
3492+
<< "ModuleTranslation Mapping Table for mapVars\n");
3493+
LLVM_DEBUG(arg.dump());
3494+
LLVM_DEBUG(llvm::dbgs() << "---->"; mapOpValue->dump());
3495+
LLVM_DEBUG(llvm::dbgs() << "\n");
33683496
moduleTranslation.mapValue(arg, mapOpValue);
33693497
}
3370-
3498+
LLVM_DEBUG(llvm::dbgs() << "LLVM Module before privatization\n");
3499+
LLVM_DEBUG(llvm::dbgs() << "------------------------------------\n");
3500+
LLVM_DEBUG(builder.GetInsertBlock()->getParent()->getParent()->dump());
3501+
LLVM_DEBUG(llvm::dbgs() << "------------------------------------\n");
33713502
// Do privatization after moduleTranslation has already recorded
33723503
// mapped values.
3504+
SmallVector<llvm::Value *> llvmPrivateVars;
3505+
SmallVector<Region *> privateCleanupRegions;
33733506
if (!targetOp.getPrivateVars().empty()) {
33743507
builder.restoreIP(allocaIP);
33753508

@@ -3384,16 +3517,18 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
33843517
SymbolRefAttr privSym = cast<SymbolRefAttr>(privatizerNameAttr);
33853518
omp::PrivateClauseOp privatizer = findPrivatizer(&opInst, privSym);
33863519
if (privatizer.getDataSharingType() ==
3387-
omp::DataSharingClauseType::FirstPrivate ||
3388-
!privatizer.getDeallocRegion().empty()) {
3520+
omp::DataSharingClauseType::FirstPrivate) {
33893521
opInst.emitError("Translation of omp.target from MLIR to LLVMIR "
3390-
"failed because translation of firstprivate and "
3391-
" private allocatables is not supported yet");
3522+
"failed because translation of firstprivate is not "
3523+
"supported yet");
33923524
bodyGenStatus = failure();
33933525
} else {
3394-
moduleTranslation.mapValue(privatizer.getAllocMoldArg(),
3395-
moduleTranslation.lookupValue(privVar));
33963526
Region &allocRegion = privatizer.getAllocRegion();
3527+
BlockArgument allocRegionArg = allocRegion.getArgument(0);
3528+
moduleTranslation.mapValue(
3529+
allocRegionArg,
3530+
findHostAssociatedValue(privVar, targetOp, mappedPrivateVars,
3531+
builder, moduleTranslation));
33973532
SmallVector<llvm::Value *, 1> yieldedValues;
33983533
if (failed(inlineConvertOmpRegions(
33993534
allocRegion, "omp.targetop.privatizer", builder,
@@ -3404,7 +3539,12 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
34043539
bodyGenStatus = failure();
34053540
} else {
34063541
assert(yieldedValues.size() == 1);
3407-
moduleTranslation.mapValue(privBlockArg, yieldedValues.front());
3542+
llvm::Value *llvmReplacementValue = yieldedValues.front();
3543+
moduleTranslation.mapValue(privBlockArg, llvmReplacementValue);
3544+
if (!privatizer.getDeallocRegion().empty()) {
3545+
llvmPrivateVars.push_back(llvmReplacementValue);
3546+
privateCleanupRegions.push_back(&privatizer.getDeallocRegion());
3547+
}
34083548
}
34093549
moduleTranslation.forgetMapping(allocRegion);
34103550
builder.restoreIP(builder.saveIP());
@@ -3414,6 +3554,19 @@ convertOmpTarget(Operation &opInst, llvm::IRBuilderBase &builder,
34143554
llvm::BasicBlock *exitBlock = convertOmpOpRegions(
34153555
targetRegion, "omp.target", builder, moduleTranslation, bodyGenStatus);
34163556
builder.SetInsertPoint(exitBlock);
3557+
if (!llvmPrivateVars.empty()) {
3558+
assert(llvmPrivateVars.size() == privateCleanupRegions.size() &&
3559+
"Number of private variables needing cleanup not equal to number"
3560+
"of privatizers with dealloc regions");
3561+
if (failed(inlineOmpRegionCleanup(
3562+
privateCleanupRegions, llvmPrivateVars, moduleTranslation,
3563+
builder, "omp.targetop.private.cleanup",
3564+
/*shouldLoadCleanupRegionArg=*/false))) {
3565+
opInst.emitError("failed to inline `dealloc` region of `omp.private` "
3566+
"op in the target region");
3567+
bodyGenStatus = failure();
3568+
}
3569+
}
34173570
return builder.saveIP();
34183571
};
34193572

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// RUN: mlir-translate -mlir-to-llvmir %s | FileCheck %s
2+
3+
llvm.func @free(!llvm.ptr)
4+
llvm.func @malloc(i64) -> !llvm.ptr
5+
omp.private {type = private} @box.heap_privatizer0 : !llvm.ptr alloc {
6+
^bb0(%arg0: !llvm.ptr):
7+
%0 = llvm.mlir.constant(1 : i32) : i32
8+
%10 = llvm.getelementptr %arg0[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
9+
%1 = llvm.load %10 : !llvm.ptr -> i64
10+
%7 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> : (i32) -> !llvm.ptr
11+
%17 = llvm.call @malloc(%1) {fir.must_be_heap = true, in_type = i32} : (i64) -> !llvm.ptr
12+
%22 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
13+
%37 = llvm.insertvalue %17, %22[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
14+
llvm.store %37, %7 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
15+
omp.yield(%7 : !llvm.ptr)
16+
} dealloc {
17+
^bb0(%arg0: !llvm.ptr):
18+
%6 = llvm.mlir.constant(0 : i64) : i64
19+
%8 = llvm.getelementptr %arg0[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
20+
%9 = llvm.load %8 : !llvm.ptr -> !llvm.ptr
21+
llvm.call @free(%9) : (!llvm.ptr) -> ()
22+
omp.yield
23+
}
24+
omp.private {type = private} @box.heap_privatizer1 : !llvm.ptr alloc {
25+
^bb0(%arg0: !llvm.ptr):
26+
%0 = llvm.mlir.constant(1 : i32) : i32
27+
%10 = llvm.getelementptr %arg0[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
28+
%1 = llvm.load %10 : !llvm.ptr -> i64
29+
%7 = llvm.alloca %0 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> : (i32) -> !llvm.ptr
30+
%17 = llvm.call @malloc(%1) {fir.must_be_heap = true, in_type = i32} : (i64) -> !llvm.ptr
31+
%22 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
32+
%37 = llvm.insertvalue %17, %22[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
33+
llvm.store %37, %7 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
34+
omp.yield(%7 : !llvm.ptr)
35+
} dealloc {
36+
^bb0(%arg0: !llvm.ptr):
37+
%6 = llvm.mlir.constant(0 : i64) : i64
38+
%8 = llvm.getelementptr %arg0[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
39+
%9 = llvm.load %8 : !llvm.ptr -> !llvm.ptr
40+
llvm.call @free(%9) : (!llvm.ptr) -> ()
41+
omp.yield
42+
}
43+
llvm.func @target_allocatable_(%arg0: !llvm.ptr {fir.bindc_name = "lb"}, %arg1: !llvm.ptr {fir.bindc_name = "ub"}, %arg2: !llvm.ptr {fir.bindc_name = "l"}) attributes {fir.internal_name = "_QPtarget_allocatable"} {
44+
%6 = llvm.mlir.constant(1 : i64) : i64
45+
%7 = llvm.alloca %6 x i32 {bindc_name = "mapped_var"} : (i64) -> !llvm.ptr
46+
%13 = llvm.alloca %6 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {bindc_name = "alloc_var0"} : (i64) -> !llvm.ptr
47+
%14 = llvm.alloca %6 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {bindc_name = "alloc_var1"} : (i64) -> !llvm.ptr
48+
%53 = omp.map.info var_ptr(%7 : !llvm.ptr, i32) map_clauses(implicit, exit_release_or_enter_alloc) capture(ByCopy) -> !llvm.ptr {name = "mapped_var"}
49+
%54 = omp.map.info var_ptr(%13 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(to) capture(ByRef) -> !llvm.ptr
50+
%55 = omp.map.info var_ptr(%14 : !llvm.ptr, !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>) map_clauses(to) capture(ByRef) -> !llvm.ptr
51+
omp.target map_entries(%53 -> %arg3, %54 -> %arg4, %55 ->%arg5 : !llvm.ptr, !llvm.ptr, !llvm.ptr) private(@box.heap_privatizer0 %13 -> %arg6, @box.heap_privatizer1 %14 -> %arg7 : !llvm.ptr, !llvm.ptr) {
52+
%64 = llvm.mlir.constant(1 : i32) : i32
53+
%65 = llvm.alloca %64 x !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)> {alignment = 8 : i64} : (i32) -> !llvm.ptr
54+
%67 = llvm.alloca %64 x i32 : (i32) -> !llvm.ptr
55+
%66 = llvm.mlir.constant(19 : i32) : i32
56+
%68 = llvm.mlir.constant(18 : i32) : i32
57+
%69 = llvm.mlir.constant(10 : i32) : i32
58+
%70 = llvm.mlir.constant(5 : i32) : i32
59+
llvm.store %70, %arg3 : i32, !llvm.ptr
60+
llvm.store %69, %67 : i32, !llvm.ptr
61+
%75 = llvm.mlir.undef : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
62+
%90 = llvm.insertvalue %67, %75[0] : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>
63+
llvm.store %90, %65 : !llvm.struct<(ptr, i64, i32, i8, i8, i8, i8)>, !llvm.ptr
64+
%91 = llvm.mlir.zero : !llvm.ptr
65+
%92 = llvm.call @_FortranAAssign(%arg6, %65, %91, %68) : (!llvm.ptr, !llvm.ptr, !llvm.ptr, i32) -> !llvm.struct<()>
66+
%93 = llvm.call @_FortranAAssign(%arg7, %65, %91, %66) : (!llvm.ptr, !llvm.ptr, !llvm.ptr, i32) -> !llvm.struct<()>
67+
omp.terminator
68+
}
69+
llvm.return
70+
}
71+
72+
73+
llvm.func @_FortranAAssign(!llvm.ptr, !llvm.ptr, !llvm.ptr, i32) -> !llvm.struct<()> attributes {fir.runtime, sym_visibility = "private"}
74+
75+
// The first set of checks ensure that we are calling the offloaded function
76+
// with the right arguments, especially the second argument which needs to
77+
// be a memory reference to the descriptor for the privatized allocatable
78+
// CHECK: define void @target_allocatable_
79+
// CHECK-NOT: define internal void
80+
// CHECK: %[[DESC_ALLOC0:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1
81+
// CHECK: %[[DESC_ALLOC1:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }, i64 1
82+
// CHECK: call void @__omp_offloading_[[OFFLOADED_FUNCTION:.*]](ptr {{[^,]+}},
83+
// CHECK-SAME: ptr %[[DESC_ALLOC0]], ptr %[[DESC_ALLOC1]])
84+
85+
// CHECK: define internal void @__omp_offloading_[[OFFLOADED_FUNCTION]]
86+
// CHECK-SAME: (ptr {{[^,]+}}, ptr %[[DESCRIPTOR_ARG0:[^,]+]],
87+
// CHECK-SAME: ptr %[[DESCRIPTOR_ARG1:.*]]) {
88+
// CHECK: %[[I0:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 },
89+
// CHECK-SAME: ptr %[[DESCRIPTOR_ARG0]], i32 0, i32 1
90+
// CHECK: %[[MALLOC_ARG0:.*]] = load i64, ptr %[[I0]]
91+
// CHECK: %[[PRIV_DESC0:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }
92+
// CHECK: %[[HEAP_PTR0:.*]] = call ptr @malloc(i64 %[[MALLOC_ARG0]])
93+
// CHECK: %[[TMP0:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8 }
94+
// CHECK-SAME: undef, ptr %[[HEAP_PTR0]], 0
95+
// CHECK: store { ptr, i64, i32, i8, i8, i8, i8 } %[[TMP0]], ptr %[[PRIV_DESC0]]
96+
97+
// CHECK: %[[I1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 },
98+
// CHECK-SAME: ptr %[[DESCRIPTOR_ARG1]], i32 0, i32 1
99+
// CHECK: %[[MALLOC_ARG1:.*]] = load i64, ptr %[[I1]]
100+
// CHECK: %[[PRIV_DESC1:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }
101+
// CHECK: %[[HEAP_PTR1:.*]] = call ptr @malloc(i64 %[[MALLOC_ARG1]])
102+
// CHECK: %[[TMP1:.*]] = insertvalue { ptr, i64, i32, i8, i8, i8, i8 }
103+
// CHECK-SAME: undef, ptr %[[HEAP_PTR1]], 0
104+
// CHECK: store { ptr, i64, i32, i8, i8, i8, i8 } %[[TMP1]], ptr %[[PRIV_DESC1]]
105+
106+
// CHECK: call {} @_FortranAAssign(ptr %[[PRIV_DESC0]]
107+
// CHECK: call {} @_FortranAAssign(ptr %[[PRIV_DESC1]]
108+
109+
// CHECK: %[[PTR0:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 },
110+
// CHECK-SAME: ptr %[[PRIV_DESC0]], i32 0, i32 0
111+
// CHECK: %[[HEAP_MEMREF0:.*]] = load ptr, ptr %[[PTR0]]
112+
// CHECK: call void @free(ptr %[[HEAP_MEMREF0]])
113+
// CHECK: %[[PTR1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8 },
114+
// CHECK-SAME: ptr %[[PRIV_DESC1]], i32 0, i32 0
115+
// CHECK: %[[HEAP_MEMREF1:.*]] = load ptr, ptr %[[PTR1]]
116+
// CHECK: call void @free(ptr %[[HEAP_MEMREF1]])

0 commit comments

Comments
 (0)