Skip to content

Commit ee4f0e1

Browse files
HerrCai0907lanza
authored andcommitted
[CIR][Dialect] Introduce StdInitializerListOp to represent high-level semantics of C++ initializer list (#1121)
I don't finish all work about `cir.initlist`. But I want to get some feedback about the cir design to make sure I am in correct way. Fixed: #777
1 parent 8b21b9f commit ee4f0e1

File tree

7 files changed

+272
-70
lines changed

7 files changed

+272
-70
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

+34
Original file line numberDiff line numberDiff line change
@@ -5292,4 +5292,38 @@ def SignBitOp : CIR_Op<"signbit", [Pure]> {
52925292
}];
52935293
}
52945294

5295+
//===----------------------------------------------------------------------===//
5296+
// StdInitializerListOp
5297+
//===----------------------------------------------------------------------===//
5298+
5299+
def StdInitializerListOp : CIR_Op<"std.initializer_list"> {
5300+
let summary = "Initialize std::initializer_list";
5301+
let description = [{
5302+
The `std.initializer_list` operation will initialize
5303+
`std::initializer_list<T>` with given arguments list.
5304+
5305+
```cpp
5306+
initializer_list<int> v{1,2,3}; // initialize v with 1, 2, 3
5307+
```
5308+
5309+
The code above will generate CIR similar as:
5310+
5311+
```mlir
5312+
%0 = cir.alloca INITLIST_TYPE, !cir.ptr<INITLIST_TYPE>
5313+
%1 = cir.const #cir.int<1>
5314+
...
5315+
cir.std.initializer_list %0 (%1 %2 %3)
5316+
```
5317+
5318+
The type of each argument should be the same as template parameter of
5319+
`std::initializer_list` (aka `T` in `std::initializer_list<T>`).
5320+
}];
5321+
let arguments = (ins StructPtr:$initList, Variadic<CIR_AnyType>:$args);
5322+
let assemblyFormat = [{
5323+
$initList ` ` `(` ($args^ `:` type($args))? `)` `:` type($initList) attr-dict
5324+
}];
5325+
5326+
let hasVerifier = 1;
5327+
}
5328+
52955329
#endif // LLVM_CLANG_CIR_DIALECT_IR_CIROPS

clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp

+21-54
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818

1919
#include "clang/AST/Decl.h"
2020
#include "clang/AST/Expr.h"
21+
#include "clang/AST/ExprCXX.h"
2122
#include "clang/AST/OperationKinds.h"
2223
#include "clang/AST/RecordLayout.h"
2324
#include "clang/AST/StmtVisitor.h"
2425
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
26+
#include "clang/CIR/Dialect/IR/CIRDialect.h"
2527
#include "clang/CIR/MissingFeatures.h"
28+
#include "llvm/ADT/SmallVector.h"
29+
#include "llvm/Support/Casting.h"
2630
#include "llvm/Support/ErrorHandling.h"
2731
#include "llvm/Support/raw_ostream.h"
2832

@@ -297,62 +301,25 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
297301
void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
298302
void VisitLambdaExpr(LambdaExpr *E);
299303
void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
300-
ASTContext &Ctx = CGF.getContext();
301-
CIRGenFunction::SourceLocRAIIObject locRAIIObject{
302-
CGF, CGF.getLoc(E->getSourceRange())};
303-
// Emit an array containing the elements. The array is externally
304-
// destructed if the std::initializer_list object is.
305-
LValue Array = CGF.emitLValue(E->getSubExpr());
306-
assert(Array.isSimple() && "initializer_list array not a simple lvalue");
307-
Address ArrayPtr = Array.getAddress();
308-
309-
const ConstantArrayType *ArrayType =
310-
Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
311-
assert(ArrayType && "std::initializer_list constructed from non-array");
312-
313-
RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
314-
RecordDecl::field_iterator Field = Record->field_begin();
315-
assert(Field != Record->field_end() &&
316-
Ctx.hasSameType(Field->getType()->getPointeeType(),
317-
ArrayType->getElementType()) &&
318-
"Expected std::initializer_list first field to be const E *");
319-
// Start pointer.
320304
auto loc = CGF.getLoc(E->getSourceRange());
321-
AggValueSlot Dest = EnsureSlot(loc, E->getType());
322-
LValue DestLV = CGF.makeAddrLValue(Dest.getAddress(), E->getType());
323-
LValue Start =
324-
CGF.emitLValueForFieldInitialization(DestLV, *Field, Field->getName());
325-
mlir::Value ArrayStart = ArrayPtr.emitRawPointer();
326-
CGF.emitStoreThroughLValue(RValue::get(ArrayStart), Start);
327-
++Field;
328-
assert(Field != Record->field_end() &&
329-
"Expected std::initializer_list to have two fields");
330-
331-
auto Builder = CGF.getBuilder();
332-
333-
auto sizeOp = Builder.getConstInt(loc, ArrayType->getSize());
334-
335-
mlir::Value Size = sizeOp.getRes();
336-
Builder.getUIntNTy(ArrayType->getSizeBitWidth());
337-
LValue EndOrLength =
338-
CGF.emitLValueForFieldInitialization(DestLV, *Field, Field->getName());
339-
if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) {
340-
// Length.
341-
CGF.emitStoreThroughLValue(RValue::get(Size), EndOrLength);
342-
} else {
343-
// End pointer.
344-
assert(Field->getType()->isPointerType() &&
345-
Ctx.hasSameType(Field->getType()->getPointeeType(),
346-
ArrayType->getElementType()) &&
347-
"Expected std::initializer_list second field to be const E *");
348-
349-
auto ArrayEnd =
350-
Builder.getArrayElement(loc, loc, ArrayPtr.getPointer(),
351-
ArrayPtr.getElementType(), Size, false);
352-
CGF.emitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength);
305+
auto builder = CGF.getBuilder();
306+
auto *subExpr =
307+
llvm::cast<MaterializeTemporaryExpr>(E->getSubExpr())->getSubExpr();
308+
llvm::SmallVector<mlir::Value> inits{};
309+
for (auto *init : llvm::cast<InitListExpr>(subExpr)->inits()) {
310+
RValue tmpInit = CGF.emitAnyExprToTemp(init);
311+
if (tmpInit.isScalar()) {
312+
inits.push_back(tmpInit.getScalarVal());
313+
} else if (tmpInit.isComplex()) {
314+
inits.push_back(tmpInit.getComplexVal());
315+
} else if (tmpInit.isAggregate()) {
316+
inits.push_back(tmpInit.getAggregatePointer());
317+
} else {
318+
llvm_unreachable("invalid temp expr type");
319+
}
353320
}
354-
assert(++Field == Record->field_end() &&
355-
"Expected std::initializer_list to only have two fields");
321+
mlir::Value dest = EnsureSlot(loc, E->getType()).getPointer();
322+
builder.create<cir::StdInitializerListOp>(loc, dest, inits);
356323
}
357324

358325
void VisitExprWithCleanups(ExprWithCleanups *E);

clang/lib/CIR/Dialect/IR/CIRDialect.cpp

+23
Original file line numberDiff line numberDiff line change
@@ -3867,6 +3867,29 @@ LogicalResult cir::CatchParamOp::verify() {
38673867
return success();
38683868
}
38693869

3870+
//===----------------------------------------------------------------------===//
3871+
// StdInitializerListOp Definitions
3872+
//===----------------------------------------------------------------------===//
3873+
3874+
LogicalResult cir::StdInitializerListOp::verify() {
3875+
auto resultType = mlir::cast<cir::StructType>(
3876+
mlir::cast<cir::PointerType>(getInitList().getType()).getPointee());
3877+
if (resultType.getMembers().size() != 2)
3878+
return emitOpError(
3879+
"std::initializer_list must be '!cir.struct' with two fields");
3880+
auto memberPtr = mlir::dyn_cast<cir::PointerType>(resultType.getMembers()[0]);
3881+
if (memberPtr == nullptr)
3882+
return emitOpError("first member type of std::initializer_list must be "
3883+
"'!cir.ptr', but provided ")
3884+
<< resultType.getMembers()[0];
3885+
auto expectedType = memberPtr.getPointee();
3886+
for (const mlir::Value &arg : getArgs())
3887+
if (expectedType != arg.getType())
3888+
return emitOpError("arg type must be ")
3889+
<< expectedType << ", but provided " << arg.getType();
3890+
return mlir::success();
3891+
}
3892+
38703893
//===----------------------------------------------------------------------===//
38713894
// TableGen'd op method definitions
38723895
//===----------------------------------------------------------------------===//

clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp

+82-1
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@
1212
#include "mlir/IR/Region.h"
1313
#include "clang/AST/ASTContext.h"
1414
#include "clang/AST/CharUnits.h"
15+
#include "clang/AST/Decl.h"
1516
#include "clang/AST/Mangle.h"
1617
#include "clang/Basic/Module.h"
1718
#include "clang/Basic/TargetInfo.h"
1819
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
1920
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
2021
#include "clang/CIR/Dialect/IR/CIRDialect.h"
22+
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
23+
#include "clang/CIR/Dialect/IR/CIRTypes.h"
2124
#include "clang/CIR/Dialect/Passes.h"
2225
#include "clang/CIR/Interfaces/ASTAttrInterfaces.h"
2326
#include "llvm/ADT/APFloat.h"
27+
#include "llvm/ADT/STLExtras.h"
2428
#include "llvm/ADT/SmallVector.h"
2529
#include "llvm/ADT/StringMap.h"
2630
#include "llvm/ADT/StringRef.h"
@@ -85,6 +89,7 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
8589
void lowerToMemCpy(StoreOp op);
8690
void lowerArrayDtor(ArrayDtor op);
8791
void lowerArrayCtor(ArrayCtor op);
92+
void lowerStdInitializerListOp(StdInitializerListOp op);
8893

8994
/// Collect annotations of global values in the module
9095
void addGlobalAnnotations(mlir::Operation *op, mlir::ArrayAttr annotations);
@@ -1120,6 +1125,79 @@ void LoweringPreparePass::lowerIterEndOp(IterEndOp op) {
11201125
op.erase();
11211126
}
11221127

1128+
/// lowering construction of std::initializer_list.
1129+
/// 1. alloca array for arg list.
1130+
/// 2. copy arg list to array.
1131+
/// 3. construct std::initializer_list from array.
1132+
void LoweringPreparePass::lowerStdInitializerListOp(StdInitializerListOp op) {
1133+
auto loc = op.getLoc();
1134+
cir::CIRDataLayout dataLayout(theModule);
1135+
auto args = op.getArgs();
1136+
1137+
auto stdInitializerListType = mlir::cast<cir::StructType>(
1138+
mlir::cast<cir::PointerType>(op.getInitList().getType()).getPointee());
1139+
clang::RecordDecl::field_range stdInitializerListFields =
1140+
stdInitializerListType.getAst().getRawDecl()->fields();
1141+
1142+
mlir::Type elementType =
1143+
mlir::cast<cir::PointerType>(stdInitializerListType.getMembers()[0])
1144+
.getPointee();
1145+
auto tempArrayType =
1146+
cir::ArrayType::get(&getContext(), elementType, args.size());
1147+
1148+
CIRBaseBuilderTy builder(getContext());
1149+
builder.setInsertionPointAfter(op);
1150+
1151+
IntegerAttr alignment = builder.getI64IntegerAttr(
1152+
dataLayout.getPrefTypeAlign(tempArrayType).value());
1153+
assert(!cir::MissingFeatures::addressSpace());
1154+
mlir::Value arrayPtr = builder.createAlloca(
1155+
loc, cir::PointerType::get(tempArrayType), tempArrayType, "", alignment);
1156+
mlir::Value arrayStartPtr =
1157+
builder.createCast(cir::CastKind::array_to_ptrdecay, arrayPtr,
1158+
cir::PointerType::get(elementType));
1159+
for (unsigned i = 0; i < args.size(); i++) {
1160+
if (i == 0) {
1161+
builder.createStore(loc, args[i], arrayStartPtr);
1162+
} else {
1163+
mlir::Value offset = builder.getUnsignedInt(loc, i, 64);
1164+
mlir::Value dest = builder.create<cir::PtrStrideOp>(
1165+
loc, arrayStartPtr.getType(), arrayStartPtr, offset);
1166+
builder.createStore(loc, args[i], dest);
1167+
}
1168+
}
1169+
1170+
// FIXME(cir): better handling according to different field type. [ptr ptr],
1171+
// [ptr size], [size ptr].
1172+
1173+
clang::RecordDecl::field_iterator it = stdInitializerListFields.begin();
1174+
const clang::RecordDecl::field_iterator startField = it;
1175+
const unsigned startIdx = 0U;
1176+
const clang::RecordDecl::field_iterator endOrSizeField = ++it;
1177+
const unsigned endOrSizeIdx = 1U;
1178+
assert(llvm::range_size(stdInitializerListFields) == 2U);
1179+
1180+
mlir::Value startMemberPtr = builder.createGetMemberOp(
1181+
loc, op.getInitList(), startField->getName().data(), startIdx);
1182+
builder.createStore(loc, arrayStartPtr, startMemberPtr);
1183+
1184+
mlir::Value size = builder.getUnsignedInt(loc, args.size(), 64);
1185+
if (endOrSizeField->getType()->isPointerType()) {
1186+
mlir::Value arrayEndPtr = builder.create<cir::PtrStrideOp>(
1187+
loc, arrayStartPtr.getType(), arrayStartPtr, size);
1188+
mlir::Value endMemberPtr = builder.createGetMemberOp(
1189+
loc, op.getInitList(), endOrSizeField->getName().data(), endOrSizeIdx);
1190+
builder.createStore(loc, arrayEndPtr, endMemberPtr);
1191+
} else {
1192+
assert(endOrSizeField->getType()->isIntegerType());
1193+
mlir::Value sizeMemberPtr = builder.createGetMemberOp(
1194+
loc, op.getInitList(), endOrSizeField->getName().data(), endOrSizeIdx);
1195+
builder.createStore(loc, size, sizeMemberPtr);
1196+
}
1197+
1198+
op.erase();
1199+
}
1200+
11231201
void LoweringPreparePass::addGlobalAnnotations(mlir::Operation *op,
11241202
mlir::ArrayAttr annotations) {
11251203
auto globalValue = cast<mlir::SymbolOpInterface>(op);
@@ -1180,6 +1258,8 @@ void LoweringPreparePass::runOnOp(Operation *op) {
11801258
}
11811259
if (std::optional<mlir::ArrayAttr> annotations = fnOp.getAnnotations())
11821260
addGlobalAnnotations(fnOp, annotations.value());
1261+
} else if (auto stdInitializerListOp = dyn_cast<StdInitializerListOp>(op)) {
1262+
lowerStdInitializerListOp(stdInitializerListOp);
11831263
}
11841264
}
11851265

@@ -1195,7 +1275,8 @@ void LoweringPreparePass::runOnOperation() {
11951275
op->walk([&](Operation *op) {
11961276
if (isa<UnaryOp, BinOp, CastOp, ComplexBinOp, CmpThreeWayOp, VAArgOp,
11971277
GlobalOp, DynamicCastOp, StdFindOp, IterEndOp, IterBeginOp,
1198-
ArrayCtor, ArrayDtor, cir::FuncOp, StoreOp>(op))
1278+
ArrayCtor, ArrayDtor, cir::FuncOp, StoreOp, StdInitializerListOp>(
1279+
op))
11991280
opsToTransform.push_back(op);
12001281
});
12011282

clang/test/CIR/CodeGen/initlist-ptr-ptr.cpp

+22-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir -clangir-disable-passes
2+
// RUN: FileCheck --check-prefix=BEFORE --input-file=%t.cir %s
13
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir
24
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
35
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-llvm -fno-clangir-call-conv-lowering %s -o %t.ll
@@ -15,6 +17,16 @@ void test() {
1517
}
1618
} // namespace std
1719

20+
// BEFORE: [[INITLIST_TYPE:!.*]] = !cir.struct<class "std::initializer_list<const char *>" {!cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!cir.ptr<!s8i>>} #cir.record.decl.ast>
21+
// BEFORE: %0 = cir.alloca [[INITLIST_TYPE]], !cir.ptr<[[INITLIST_TYPE]]>,
22+
// BEFORE: %1 = cir.get_global @".str" : !cir.ptr<!cir.array<!s8i x 3>>
23+
// BEFORE: %2 = cir.cast(array_to_ptrdecay, %1 : !cir.ptr<!cir.array<!s8i x 3>>), !cir.ptr<!s8i>
24+
// BEFORE: %3 = cir.get_global @".str.1" : !cir.ptr<!cir.array<!s8i x 3>>
25+
// BEFORE: %4 = cir.cast(array_to_ptrdecay, %3 : !cir.ptr<!cir.array<!s8i x 3>>), !cir.ptr<!s8i>
26+
// BEFORE: cir.std.initializer_list %0 (%2, %4 : !cir.ptr<!s8i>, !cir.ptr<!s8i>) : !cir.ptr<[[INITLIST_TYPE]]>
27+
// BEFORE: %5 = cir.load %0 : !cir.ptr<[[INITLIST_TYPE]]>, [[INITLIST_TYPE]]
28+
// BEFORE: cir.call @_ZSt1fIPKcEvSt16initializer_listIT_E(%5) : ([[INITLIST_TYPE]]) -> ()
29+
1830
// CIR: [[INITLIST_TYPE:!.*]] = !cir.struct<class "std::initializer_list<const char *>" {!cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!cir.ptr<!s8i>>}>
1931
// CIR: cir.func linkonce_odr @_ZSt1fIPKcEvSt16initializer_listIT_E(%arg0: [[INITLIST_TYPE]]
2032
// CIR: [[LOCAL:%.*]] = cir.alloca [[INITLIST_TYPE]], !cir.ptr<[[INITLIST_TYPE]]>,
@@ -27,24 +39,22 @@ void test() {
2739
// CIR: cir.func @_ZSt4testv()
2840
// CIR: cir.scope {
2941
// CIR: [[INITLIST_LOCAL:%.*]] = cir.alloca [[INITLIST_TYPE]], !cir.ptr<[[INITLIST_TYPE]]>,
30-
// CIR: [[LOCAL_ELEM_ARRAY:%.*]] = cir.alloca !cir.array<!cir.ptr<!s8i> x 2>, !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>,
31-
// CIR: [[FIRST_ELEM_PTR:%.*]] = cir.cast(array_to_ptrdecay, [[LOCAL_ELEM_ARRAY]] : !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>), !cir.ptr<!cir.ptr<!s8i>>
3242
// CIR: [[XY_CHAR_ARRAY:%.*]] = cir.get_global [[STR_XY]] : !cir.ptr<!cir.array<!s8i x 3>>
3343
// CIR: [[STR_XY_PTR:%.*]] = cir.cast(array_to_ptrdecay, [[XY_CHAR_ARRAY]] : !cir.ptr<!cir.array<!s8i x 3>>), !cir.ptr<!s8i>
34-
// CIR: cir.store [[STR_XY_PTR]], [[FIRST_ELEM_PTR]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
35-
// CIR: [[ONE:%.*]] = cir.const #cir.int<1>
36-
// CIR: [[NEXT_ELEM_PTR:%.*]] = cir.ptr_stride([[FIRST_ELEM_PTR]] : !cir.ptr<!cir.ptr<!s8i>>, [[ONE]] : !s64i), !cir.ptr<!cir.ptr<!s8i>>
3744
// CIR: [[UV_CHAR_ARRAY:%.*]] = cir.get_global [[STR_UV]] : !cir.ptr<!cir.array<!s8i x 3>>
3845
// CIR: [[STR_UV_PTR:%.*]] = cir.cast(array_to_ptrdecay, [[UV_CHAR_ARRAY]] : !cir.ptr<!cir.array<!s8i x 3>>), !cir.ptr<!s8i>
46+
// CIR: [[LOCAL_ELEM_ARRAY:%.*]] = cir.alloca !cir.array<!cir.ptr<!s8i> x 2>, !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>,
47+
// CIR: [[ELEM_BEGIN:%.*]] = cir.cast(array_to_ptrdecay, [[LOCAL_ELEM_ARRAY]] : !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>), !cir.ptr<!cir.ptr<!s8i>>
48+
// CIR: cir.store [[STR_XY_PTR]], [[ELEM_BEGIN]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
49+
// CIR: [[ONE:%.*]] = cir.const #cir.int<1>
50+
// CIR: [[NEXT_ELEM_PTR:%.*]] = cir.ptr_stride([[ELEM_BEGIN]] : !cir.ptr<!cir.ptr<!s8i>>, [[ONE]] : !u64i), !cir.ptr<!cir.ptr<!s8i>>
3951
// CIR: cir.store [[STR_UV_PTR]], [[NEXT_ELEM_PTR]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
4052
// CIR: [[START_FLD_PTR:%.*]] = cir.get_member [[INITLIST_LOCAL]][0] {name = "array_start"} : !cir.ptr<[[INITLIST_TYPE]]> -> !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>
41-
// CIR: [[START_FLD_PTR_AS_PTR_2_CHAR_ARRAY:%.*]] = cir.cast(bitcast, [[START_FLD_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>), !cir.ptr<!cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>>
42-
// CIR: cir.store [[LOCAL_ELEM_ARRAY]], [[START_FLD_PTR_AS_PTR_2_CHAR_ARRAY]] : !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>, !cir.ptr<!cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>>
53+
// CIR: cir.store [[ELEM_BEGIN]], [[START_FLD_PTR]] : !cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>
4354
// CIR: [[ELEM_ARRAY_LEN:%.*]] = cir.const #cir.int<2>
55+
// CIR: [[ELEM_END:%.*]] = cir.ptr_stride([[ELEM_BEGIN]] : !cir.ptr<!cir.ptr<!s8i>>, [[ELEM_ARRAY_LEN]] : !u64i), !cir.ptr<!cir.ptr<!s8i>>
4456
// CIR: [[END_FLD_PTR:%.*]] = cir.get_member [[INITLIST_LOCAL]][1] {name = "array_end"} : !cir.ptr<[[INITLIST_TYPE]]> -> !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>
45-
// CIR: [[LOCAL_ELEM_ARRAY_END:%.*]] = cir.ptr_stride([[LOCAL_ELEM_ARRAY]] : !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>, [[ELEM_ARRAY_LEN]] : !u64i), !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>
46-
// CIR: [[END_FLD_PTR_AS_PTR_2_CHAR_ARRAY:%.*]] = cir.cast(bitcast, [[END_FLD_PTR]] : !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>), !cir.ptr<!cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>>
47-
// CIR: cir.store [[LOCAL_ELEM_ARRAY_END]], [[END_FLD_PTR_AS_PTR_2_CHAR_ARRAY]] : !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>, !cir.ptr<!cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>>
57+
// CIR: cir.store [[ELEM_END]], [[END_FLD_PTR]] : !cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>
4858
// CIR: [[ARG:%.*]] = cir.load [[INITLIST_LOCAL]] : !cir.ptr<[[INITLIST_TYPE]]>, [[INITLIST_TYPE]]
4959
// CIR: cir.call @_ZSt1fIPKcEvSt16initializer_listIT_E([[ARG]]) : ([[INITLIST_TYPE]]) -> ()
5060
// CIR: }
@@ -72,8 +82,9 @@ void test() {
7282
// LLVM: [[PTR_SECOND_ELEM:%.*]] = getelementptr ptr, ptr [[PTR_FIRST_ELEM]], i64 1,
7383
// LLVM: store ptr @.str.1, ptr [[PTR_SECOND_ELEM]], align 8,
7484
// LLVM: [[INIT_START_FLD_PTR:%.*]] = getelementptr %"class.std::initializer_list<const char *>", ptr [[INIT_STRUCT]], i32 0, i32 0,
85+
// LLVM: store ptr [[PTR_FIRST_ELEM]], ptr [[INIT_START_FLD_PTR]], align 8,
86+
// LLVM: [[ELEM_ARRAY_END:%.*]] = getelementptr ptr, ptr [[PTR_FIRST_ELEM]], i64 2,
7587
// LLVM: [[INIT_END_FLD_PTR:%.*]] = getelementptr %"class.std::initializer_list<const char *>", ptr [[INIT_STRUCT]], i32 0, i32 1,
76-
// LLVM: [[ELEM_ARRAY_END:%.*]] = getelementptr [2 x ptr], ptr [[ELEM_ARRAY_PTR]], i64 2,
7788
// LLVM: store ptr [[ELEM_ARRAY_END]], ptr [[INIT_END_FLD_PTR]], align 8,
7889
// LLVM: [[ARG2PASS:%.*]] = load %"class.std::initializer_list<const char *>", ptr [[INIT_STRUCT]], align 8,
7990
// LLVM: call void @_ZSt1fIPKcEvSt16initializer_listIT_E(%"class.std::initializer_list<const char *>" [[ARG2PASS]]),

0 commit comments

Comments
 (0)