Skip to content

Commit f677c5e

Browse files
committed
[flang] Initial lowering of SELECT TYPE construct to fir.select_type operation
This patch is the initial path to lower the SELECT TYPE construct to the fir.select_type operation. More work is required in the AssocEntity mapping but it will be done in a follow up patch to ease the review. Reviewed By: jeanPerier Differential Revision: https://reviews.llvm.org/D137728
1 parent ce879a0 commit f677c5e

File tree

5 files changed

+331
-11
lines changed

5 files changed

+331
-11
lines changed

flang/include/flang/Optimizer/Builder/BoxValue.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,14 @@ class ExtendedValue : public details::matcher<ExtendedValue> {
517517
[](const auto &box) -> unsigned { return box.rank(); });
518518
}
519519

520+
bool isPolymorphic() const {
521+
return match([](const fir::PolymorphicValue &box) -> bool { return true; },
522+
[](const fir::ArrayBoxValue &box) -> bool {
523+
return box.getTdesc() ? true : false;
524+
},
525+
[](const auto &box) -> bool { return false; });
526+
}
527+
520528
/// Is this an assumed size array ?
521529
bool isAssumedSize() const;
522530

flang/lib/Lower/Bridge.cpp

Lines changed: 142 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2100,14 +2100,146 @@ class FirConverter : public Fortran::lower::AbstractConverter {
21002100
}
21012101

21022102
void genFIR(const Fortran::parser::SelectTypeConstruct &selectTypeConstruct) {
2103-
setCurrentPositionAt(selectTypeConstruct);
2104-
TODO(toLocation(), "SelectTypeConstruct implementation");
2105-
}
2106-
void genFIR(const Fortran::parser::SelectTypeStmt &) {
2107-
TODO(toLocation(), "SelectTypeStmt implementation");
2108-
}
2109-
void genFIR(const Fortran::parser::TypeGuardStmt &) {
2110-
TODO(toLocation(), "TypeGuardStmt implementation");
2103+
mlir::Location loc = toLocation();
2104+
mlir::MLIRContext *context = builder->getContext();
2105+
Fortran::lower::StatementContext stmtCtx;
2106+
fir::ExtendedValue selector;
2107+
llvm::SmallVector<mlir::Attribute> attrList;
2108+
llvm::SmallVector<mlir::Block *> blockList;
2109+
unsigned typeGuardIdx = 0;
2110+
bool hasLocalScope = false;
2111+
2112+
for (Fortran::lower::pft::Evaluation &eval :
2113+
getEval().getNestedEvaluations()) {
2114+
if (auto *selectTypeStmt =
2115+
eval.getIf<Fortran::parser::SelectTypeStmt>()) {
2116+
// Retrieve the selector
2117+
const auto &s = std::get<Fortran::parser::Selector>(selectTypeStmt->t);
2118+
if (const auto *v = std::get_if<Fortran::parser::Variable>(&s.u))
2119+
selector = genExprBox(loc, *Fortran::semantics::GetExpr(*v), stmtCtx);
2120+
else
2121+
fir::emitFatalError(
2122+
loc, "selector with expr not expected in select type statement");
2123+
2124+
// Going through the controlSuccessor first to create the
2125+
// fir.select_type operation.
2126+
mlir::Block *defaultBlock = eval.parentConstruct->constructExit->block;
2127+
for (Fortran::lower::pft::Evaluation *e = eval.controlSuccessor; e;
2128+
e = e->controlSuccessor) {
2129+
const auto &typeGuardStmt =
2130+
e->getIf<Fortran::parser::TypeGuardStmt>();
2131+
const auto &guard =
2132+
std::get<Fortran::parser::TypeGuardStmt::Guard>(typeGuardStmt->t);
2133+
assert(e->block && "missing TypeGuardStmt block");
2134+
// CLASS DEFAULT
2135+
if (std::holds_alternative<Fortran::parser::Default>(guard.u)) {
2136+
defaultBlock = e->block;
2137+
continue;
2138+
}
2139+
2140+
blockList.push_back(e->block);
2141+
if (const auto *typeSpec =
2142+
std::get_if<Fortran::parser::TypeSpec>(&guard.u)) {
2143+
// TYPE IS
2144+
mlir::Type ty;
2145+
if (std::holds_alternative<Fortran::parser::IntrinsicTypeSpec>(
2146+
typeSpec->u)) {
2147+
const Fortran::semantics::IntrinsicTypeSpec *intrinsic =
2148+
typeSpec->declTypeSpec->AsIntrinsic();
2149+
int kind =
2150+
Fortran::evaluate::ToInt64(intrinsic->kind()).value_or(kind);
2151+
llvm::SmallVector<Fortran::lower::LenParameterTy> params;
2152+
if (intrinsic->category() ==
2153+
Fortran::common::TypeCategory::Character ||
2154+
intrinsic->category() ==
2155+
Fortran::common::TypeCategory::Derived)
2156+
TODO(loc, "typeSpec with length parameters");
2157+
ty = genType(intrinsic->category(), kind, params);
2158+
} else {
2159+
const Fortran::semantics::DerivedTypeSpec *derived =
2160+
typeSpec->declTypeSpec->AsDerived();
2161+
ty = genType(*derived);
2162+
}
2163+
attrList.push_back(fir::ExactTypeAttr::get(ty));
2164+
} else if (const auto *derived =
2165+
std::get_if<Fortran::parser::DerivedTypeSpec>(
2166+
&guard.u)) {
2167+
// CLASS IS
2168+
assert(derived->derivedTypeSpec && "derived type spec is null");
2169+
mlir::Type ty = genType(*(derived->derivedTypeSpec));
2170+
attrList.push_back(fir::SubclassAttr::get(ty));
2171+
}
2172+
}
2173+
attrList.push_back(mlir::UnitAttr::get(context));
2174+
blockList.push_back(defaultBlock);
2175+
builder->create<fir::SelectTypeOp>(loc, fir::getBase(selector),
2176+
attrList, blockList);
2177+
} else if (auto *typeGuardStmt =
2178+
eval.getIf<Fortran::parser::TypeGuardStmt>()) {
2179+
// Map the type guard local symbol for the selector to a more precise
2180+
// typed entity in the TypeGuardStmt when necessary.
2181+
const auto &guard =
2182+
std::get<Fortran::parser::TypeGuardStmt::Guard>(typeGuardStmt->t);
2183+
if (hasLocalScope)
2184+
localSymbols.popScope();
2185+
localSymbols.pushScope();
2186+
hasLocalScope = true;
2187+
assert(attrList.size() >= typeGuardIdx &&
2188+
"TypeGuard attribute missing");
2189+
mlir::Attribute typeGuardAttr = attrList[typeGuardIdx];
2190+
mlir::Block *typeGuardBlock = blockList[typeGuardIdx];
2191+
const Fortran::semantics::Scope &guardScope =
2192+
bridge.getSemanticsContext().FindScope(eval.position);
2193+
mlir::OpBuilder::InsertPoint crtInsPt = builder->saveInsertionPoint();
2194+
builder->setInsertionPointToStart(typeGuardBlock);
2195+
2196+
auto addAssocEntitySymbol = [&](fir::ExtendedValue exv) {
2197+
for (auto &symbol : guardScope.GetSymbols()) {
2198+
if (symbol->GetUltimate()
2199+
.detailsIf<Fortran::semantics::AssocEntityDetails>()) {
2200+
localSymbols.addSymbol(symbol, exv);
2201+
break;
2202+
}
2203+
}
2204+
};
2205+
2206+
if (std::holds_alternative<Fortran::parser::Default>(guard.u)) {
2207+
// CLASS DEFAULT
2208+
addAssocEntitySymbol(selector);
2209+
} else if (const auto *typeSpec =
2210+
std::get_if<Fortran::parser::TypeSpec>(&guard.u)) {
2211+
// TYPE IS
2212+
fir::ExactTypeAttr attr =
2213+
typeGuardAttr.dyn_cast<fir::ExactTypeAttr>();
2214+
mlir::Value exactValue;
2215+
if (std::holds_alternative<Fortran::parser::IntrinsicTypeSpec>(
2216+
typeSpec->u)) {
2217+
exactValue = builder->create<fir::BoxAddrOp>(
2218+
loc, fir::ReferenceType::get(attr.getType()),
2219+
fir::getBase(selector));
2220+
} else if (std::holds_alternative<Fortran::parser::DerivedTypeSpec>(
2221+
typeSpec->u)) {
2222+
exactValue = builder->create<fir::ConvertOp>(
2223+
loc, fir::BoxType::get(attr.getType()), fir::getBase(selector));
2224+
}
2225+
addAssocEntitySymbol(exactValue);
2226+
} else if (std::holds_alternative<Fortran::parser::DerivedTypeSpec>(
2227+
guard.u)) {
2228+
// CLASS IS
2229+
fir::SubclassAttr attr = typeGuardAttr.dyn_cast<fir::SubclassAttr>();
2230+
mlir::Value derived = builder->create<fir::ConvertOp>(
2231+
loc, fir::ClassType::get(attr.getType()), fir::getBase(selector));
2232+
addAssocEntitySymbol(derived);
2233+
}
2234+
builder->restoreInsertionPoint(crtInsPt);
2235+
++typeGuardIdx;
2236+
} else if (eval.getIf<Fortran::parser::EndSelectStmt>()) {
2237+
if (hasLocalScope)
2238+
localSymbols.popScope();
2239+
stmtCtx.finalize();
2240+
}
2241+
genFIR(eval);
2242+
}
21112243
}
21122244

21132245
//===--------------------------------------------------------------------===//
@@ -2755,6 +2887,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
27552887
void genFIR(const Fortran::parser::IfThenStmt &) {} // nop
27562888
void genFIR(const Fortran::parser::NonLabelDoStmt &) {} // nop
27572889
void genFIR(const Fortran::parser::OmpEndLoopDirective &) {} // nop
2890+
void genFIR(const Fortran::parser::SelectTypeStmt &) {} // nop
2891+
void genFIR(const Fortran::parser::TypeGuardStmt &) {} // nop
27582892

27592893
void genFIR(const Fortran::parser::NamelistStmt &) {
27602894
TODO(toLocation(), "NamelistStmt lowering");

flang/lib/Lower/ConvertExpr.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4162,7 +4162,7 @@ class ArrayExprLowering {
41624162
mlir::Value convertElementForUpdate(mlir::Location loc, mlir::Type eleTy,
41634163
mlir::Value origVal) {
41644164
if (auto origEleTy = fir::dyn_cast_ptrEleTy(origVal.getType()))
4165-
if (origEleTy.isa<fir::BoxType>()) {
4165+
if (origEleTy.isa<fir::BaseBoxType>()) {
41664166
// If origVal is a box variable, load it so it is in the value domain.
41674167
origVal = builder.create<fir::LoadOp>(loc, origVal);
41684168
}
@@ -7645,8 +7645,8 @@ fir::ExtendedValue Fortran::lower::createBoxValue(
76457645
}
76467646
fir::ExtendedValue addr = Fortran::lower::createSomeExtendedAddress(
76477647
loc, converter, expr, symMap, stmtCtx);
7648-
fir::ExtendedValue result =
7649-
fir::BoxValue(converter.getFirOpBuilder().createBox(loc, addr));
7648+
fir::ExtendedValue result = fir::BoxValue(
7649+
converter.getFirOpBuilder().createBox(loc, addr, addr.isPolymorphic()));
76507650
if (isParentComponent(expr))
76517651
result = updateBoxForParentComponent(converter, result, expr);
76527652
return result;

flang/lib/Lower/SymbolMap.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ void Fortran::lower::SymMap::addSymbol(Fortran::semantics::SymbolRef sym,
2626
[&](const fir::CharArrayBoxValue &v) { makeSym(sym, v, force); },
2727
[&](const fir::BoxValue &v) { makeSym(sym, v, force); },
2828
[&](const fir::MutableBoxValue &v) { makeSym(sym, v, force); },
29+
[&](const fir::PolymorphicValue &v) { makeSym(sym, v, force); },
2930
[](auto) {
3031
llvm::report_fatal_error("value not added to symbol table");
3132
});

flang/test/Lower/select-type.f90

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
! RUN: bbc -polymorphic-type -emit-fir %s -o - | FileCheck %s
2+
3+
module select_type_lower_test
4+
type p1
5+
integer :: a
6+
integer :: b
7+
end type
8+
9+
type, extends(p1) :: p2
10+
integer :: c
11+
end type
12+
13+
type, extends(p1) :: p3(k)
14+
integer, kind :: k
15+
real(k) :: r
16+
end type
17+
18+
contains
19+
20+
function get_class()
21+
class(p1), pointer :: get_class
22+
end function
23+
24+
subroutine select_type1(a)
25+
class(p1), intent(in) :: a
26+
27+
select type (a)
28+
type is (p1)
29+
print*, 'type is p1'
30+
class is (p1)
31+
print*, 'class is p1'
32+
class is (p2)
33+
print*, 'class is p2', a%c
34+
class default
35+
print*,'default'
36+
end select
37+
end subroutine
38+
39+
! CHECK-LABEL: func.func @_QMselect_type_lower_testPselect_type1(
40+
! CHECK-SAME: %[[ARG0:.*]]: !fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>> {fir.bindc_name = "a"})
41+
42+
! CHECK: fir.select_type %[[ARG0]] : !fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>
43+
! CHECK-SAME: [#fir.type_is<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>, ^[[TYPE_IS_BLK:.*]], #fir.class_is<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>, ^[[CLASS_IS_P1_BLK:.*]], #fir.class_is<!fir.type<_QMselect_type_lower_testTp2{a:i32,b:i32,c:i32}>>, ^[[CLASS_IS_P2_BLK:.*]], unit, ^[[DEFAULT_BLOCK:.*]]]
44+
! CHECK: ^[[TYPE_IS_BLK]]
45+
! CHECK: ^[[CLASS_IS_P1_BLK]]
46+
! CHECK: ^[[CLASS_IS_P2_BLK]]
47+
! CHECK: %[[P2:.*]] = fir.convert %[[ARG0:.*]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.class<!fir.type<_QMselect_type_lower_testTp2{a:i32,b:i32,c:i32}>>
48+
! CHECK: %[[FIELD:.*]] = fir.field_index c, !fir.type<_QMselect_type_lower_testTp2{a:i32,b:i32,c:i32}>
49+
! CHECK: %{{.*}} = fir.coordinate_of %[[P2]], %[[FIELD]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp2{a:i32,b:i32,c:i32}>>, !fir.field) -> !fir.ref<i32>
50+
! CHECK: ^[[DEFAULT_BLOCK]]
51+
52+
subroutine select_type2()
53+
select type (a => get_class())
54+
type is (p1)
55+
print*, 'type is p1'
56+
class is (p1)
57+
print*, 'class is p1'
58+
class default
59+
print*,'default'
60+
end select
61+
end subroutine
62+
63+
! CHECK-LABEL: func.func @_QMselect_type_lower_testPselect_type2()
64+
! CHECK: %[[RESULT:.*]] = fir.alloca !fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>> {bindc_name = ".result"}
65+
! CHECK: %[[FCTCALL:.*]] = fir.call @_QMselect_type_lower_testPget_class() : () -> !fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>
66+
! CHECK: fir.save_result %[[FCTCALL]] to %[[RESULT]] : !fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>, !fir.ref<!fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>>
67+
! CHECK: %[[SELECTOR:.*]] = fir.load %[[RESULT]] : !fir.ref<!fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>>
68+
! CHECK: fir.select_type %[[SELECTOR]] : !fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>
69+
! CHECK-SAME: [#fir.type_is<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>, ^[[TYPE_IS_BLK:.*]], #fir.class_is<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>, ^[[CLASS_IS_BLK:.*]], unit, ^[[DEFAULT_BLK:.*]]]
70+
! CHECK: ^[[TYPE_IS_BLK]]
71+
! CHECK: ^[[CLASS_IS_BLK]]
72+
! CHECK: ^[[DEFAULT_BLK]]
73+
74+
subroutine select_type3(a)
75+
class(p1), pointer, intent(in) :: a(:)
76+
77+
select type (x => a(1))
78+
type is (p1)
79+
print*, 'type is p1'
80+
class is (p1)
81+
print*, 'class is p1'
82+
class default
83+
print*,'default'
84+
end select
85+
end subroutine
86+
87+
! CHECK-LABEL: func.func @_QMselect_type_lower_testPselect_type3(
88+
! CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>>> {fir.bindc_name = "a"})
89+
! CHECK: %[[ARG0_LOAD:.*]] = fir.load %[[ARG0]] : !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>>>
90+
! CHECK: %[[COORD:.*]] = fir.coordinate_of %[[ARG0_LOAD]], %{{.*}} : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>>, i64) -> !fir.ref<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>
91+
! CHECK: %[[TDESC:.*]] = fir.box_tdesc %[[ARG0_LOAD]] : (!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>>) -> !fir.tdesc<none>
92+
! CHECK: %[[SELECTOR:.*]] = fir.embox %[[COORD]] tdesc %[[TDESC]] : (!fir.ref<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>, !fir.tdesc<none>) -> !fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>
93+
! CHECK: fir.select_type %[[SELECTOR]] : !fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>
94+
! CHECK-SAME: [#fir.type_is<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>, ^[[TYPE_IS_BLK:.*]], #fir.class_is<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>, ^[[CLASS_IS_BLK:.*]], unit, ^[[DEFAULT_BLK:.*]]]
95+
! CHECK: ^[[TYPE_IS_BLK]]
96+
! CHECK: ^[[CLASS_IS_BLK]]
97+
! CHECK: ^[[DEFAULT_BLK]]
98+
99+
subroutine select_type4(a)
100+
class(p1), intent(in) :: a
101+
select type(a)
102+
type is(p3(8))
103+
print*, 'type is p3(8)'
104+
type is(p3(4))
105+
print*, 'type is p3(4)'
106+
class is (p1)
107+
print*, 'class is p1'
108+
end select
109+
end subroutine
110+
111+
! CHECK-LABEL: func.func @_QMselect_type_lower_testPselect_type4(
112+
! CHECK-SAME: %[[ARG0:.*]]: !fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>> {fir.bindc_name = "a"})
113+
! CHECK: fir.select_type %[[ARG0]] : !fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>
114+
! CHECK-SAME: [#fir.type_is<!fir.type<_QMselect_type_lower_testTp3K8{a:i32,b:i32,r:f64}>>, ^[[P3_8:.*]], #fir.type_is<!fir.type<_QMselect_type_lower_testTp3K4{a:i32,b:i32,r:f32}>>, ^[[P3_4:.*]], #fir.class_is<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>, ^[[P1:.*]], unit, ^[[EXIT:.*]]]
115+
! CHECK: ^[[P3_8]]
116+
! CHECK: ^[[P3_4]]
117+
! CHECK: ^[[P1]]
118+
! CHECK: ^[[EXIT]]
119+
120+
subroutine select_type5(a)
121+
class(*), intent(in) :: a
122+
123+
select type (x => a)
124+
type is (integer(1))
125+
print*, 'type is integer(1)'
126+
type is (integer(4))
127+
print*, 'type is integer(4)'
128+
type is (real(4))
129+
print*, 'type is real'
130+
type is (logical)
131+
print*, 'type is logical'
132+
class default
133+
print*,'default'
134+
end select
135+
end subroutine
136+
137+
! CHECK-LABEL: func.func @_QMselect_type_lower_testPselect_type5(
138+
! CHECK-SAME: %[[ARG0:.*]]: !fir.class<none> {fir.bindc_name = "a"})
139+
! CHECK: fir.select_type %[[ARG0]] : !fir.class<none>
140+
! CHECK-SAME: [#fir.type_is<i8>, ^[[I8_BLK:.*]], #fir.type_is<i32>, ^[[I32_BLK:.*]], #fir.type_is<f32>, ^[[F32_BLK:.*]], #fir.type_is<!fir.logical<4>>, ^[[LOG_BLK:.*]], unit, ^[[DEFAULT:.*]]]
141+
! CHECK: ^[[I8_BLK]]
142+
! CHECK: ^[[I32_BLK]]
143+
! CHECK: ^[[F32_BLK]]
144+
! CHECK: ^[[LOG_BLK]]
145+
! CHECK: ^[[DEFAULT_BLOCK]]
146+
147+
148+
subroutine select_type6(a)
149+
class(*), intent(out) :: a
150+
151+
select type(a)
152+
type is (integer)
153+
a = 100
154+
type is (real)
155+
a = 2.0
156+
class default
157+
stop 'error'
158+
end select
159+
end subroutine
160+
161+
! CHECK-LABEL: func.func @_QMselect_type_lower_testPselect_type6(
162+
! CHECK-SAME: %[[ARG0:.*]]: !fir.class<none> {fir.bindc_name = "a"})
163+
164+
! CHECK: fir.select_type %[[ARG0]] : !fir.class<none> [#fir.type_is<i32>, ^[[INT_BLK:.*]], #fir.type_is<f32>, ^[[REAL_BLK:.*]], unit, ^[[DEFAULT_BLK:.*]]]
165+
! CHECK: ^[[INT_BLK]]
166+
! CHECK: %[[BOX_ADDR:.*]] = fir.box_addr %[[ARG0]] : (!fir.class<none>) -> !fir.ref<i32>
167+
! CHECK: %[[C100:.*]] = arith.constant 100 : i32
168+
! CHECK: fir.store %[[C100]] to %[[BOX_ADDR]] : !fir.ref<i32>
169+
170+
! CHECK: ^[[REAL_BLK]]: // pred: ^bb0
171+
! CHECK: %[[BOX_ADDR:.*]] = fir.box_addr %[[ARG0]] : (!fir.class<none>) -> !fir.ref<f32>
172+
! CHECK: %[[C2:.*]] = arith.constant 2.000000e+00 : f32
173+
! CHECK: fir.store %[[C2]] to %[[BOX_ADDR]] : !fir.ref<f32>
174+
175+
end module
176+
177+

0 commit comments

Comments
 (0)