Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CIR] revert StdInitializerListOp #1216

Merged
merged 1 commit into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 0 additions & 34 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -5336,38 +5336,4 @@ def SignBitOp : CIR_Op<"signbit", [Pure]> {
}];
}

//===----------------------------------------------------------------------===//
// StdInitializerListOp
//===----------------------------------------------------------------------===//

def StdInitializerListOp : CIR_Op<"std.initializer_list"> {
let summary = "Initialize std::initializer_list";
let description = [{
The `std.initializer_list` operation will initialize
`std::initializer_list<T>` with given arguments list.

```cpp
initializer_list<int> v{1,2,3}; // initialize v with 1, 2, 3
```

The code above will generate CIR similar as:

```mlir
%0 = cir.alloca INITLIST_TYPE, !cir.ptr<INITLIST_TYPE>
%1 = cir.const #cir.int<1>
...
cir.std.initializer_list %0 (%1 %2 %3)
```

The type of each argument should be the same as template parameter of
`std::initializer_list` (aka `T` in `std::initializer_list<T>`).
}];
let arguments = (ins StructPtr:$initList, Variadic<CIR_AnyType>:$args);
let assemblyFormat = [{
$initList ` ` `(` ($args^ `:` type($args))? `)` `:` type($initList) attr-dict
}];

let hasVerifier = 1;
}

#endif // LLVM_CLANG_CIR_DIALECT_IR_CIROPS
75 changes: 54 additions & 21 deletions clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,11 @@

#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/OperationKinds.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/CIR/Dialect/IR/CIRAttrs.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/MissingFeatures.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"

Expand Down Expand Up @@ -301,25 +297,62 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
void VisitLambdaExpr(LambdaExpr *E);
void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) {
ASTContext &Ctx = CGF.getContext();
CIRGenFunction::SourceLocRAIIObject locRAIIObject{
CGF, CGF.getLoc(E->getSourceRange())};
// Emit an array containing the elements. The array is externally
// destructed if the std::initializer_list object is.
LValue Array = CGF.emitLValue(E->getSubExpr());
assert(Array.isSimple() && "initializer_list array not a simple lvalue");
Address ArrayPtr = Array.getAddress();

const ConstantArrayType *ArrayType =
Ctx.getAsConstantArrayType(E->getSubExpr()->getType());
assert(ArrayType && "std::initializer_list constructed from non-array");

RecordDecl *Record = E->getType()->castAs<RecordType>()->getDecl();
RecordDecl::field_iterator Field = Record->field_begin();
assert(Field != Record->field_end() &&
Ctx.hasSameType(Field->getType()->getPointeeType(),
ArrayType->getElementType()) &&
"Expected std::initializer_list first field to be const E *");
// Start pointer.
auto loc = CGF.getLoc(E->getSourceRange());
auto builder = CGF.getBuilder();
auto *subExpr =
llvm::cast<MaterializeTemporaryExpr>(E->getSubExpr())->getSubExpr();
llvm::SmallVector<mlir::Value> inits{};
for (auto *init : llvm::cast<InitListExpr>(subExpr)->inits()) {
RValue tmpInit = CGF.emitAnyExprToTemp(init);
if (tmpInit.isScalar()) {
inits.push_back(tmpInit.getScalarVal());
} else if (tmpInit.isComplex()) {
inits.push_back(tmpInit.getComplexVal());
} else if (tmpInit.isAggregate()) {
inits.push_back(tmpInit.getAggregatePointer());
} else {
llvm_unreachable("invalid temp expr type");
}
AggValueSlot Dest = EnsureSlot(loc, E->getType());
LValue DestLV = CGF.makeAddrLValue(Dest.getAddress(), E->getType());
LValue Start =
CGF.emitLValueForFieldInitialization(DestLV, *Field, Field->getName());
mlir::Value ArrayStart = ArrayPtr.emitRawPointer();
CGF.emitStoreThroughLValue(RValue::get(ArrayStart), Start);
++Field;
assert(Field != Record->field_end() &&
"Expected std::initializer_list to have two fields");

auto Builder = CGF.getBuilder();

auto sizeOp = Builder.getConstInt(loc, ArrayType->getSize());

mlir::Value Size = sizeOp.getRes();
Builder.getUIntNTy(ArrayType->getSizeBitWidth());
LValue EndOrLength =
CGF.emitLValueForFieldInitialization(DestLV, *Field, Field->getName());
if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) {
// Length.
CGF.emitStoreThroughLValue(RValue::get(Size), EndOrLength);
} else {
// End pointer.
assert(Field->getType()->isPointerType() &&
Ctx.hasSameType(Field->getType()->getPointeeType(),
ArrayType->getElementType()) &&
"Expected std::initializer_list second field to be const E *");

auto ArrayEnd =
Builder.getArrayElement(loc, loc, ArrayPtr.getPointer(),
ArrayPtr.getElementType(), Size, false);
CGF.emitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength);
}
mlir::Value dest = EnsureSlot(loc, E->getType()).getPointer();
builder.create<cir::StdInitializerListOp>(loc, dest, inits);
assert(++Field == Record->field_end() &&
"Expected std::initializer_list to only have two fields");
}

void VisitExprWithCleanups(ExprWithCleanups *E);
Expand Down
23 changes: 0 additions & 23 deletions clang/lib/CIR/Dialect/IR/CIRDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3865,29 +3865,6 @@ LogicalResult cir::CatchParamOp::verify() {
return success();
}

//===----------------------------------------------------------------------===//
// StdInitializerListOp Definitions
//===----------------------------------------------------------------------===//

LogicalResult cir::StdInitializerListOp::verify() {
auto resultType = mlir::cast<cir::StructType>(
mlir::cast<cir::PointerType>(getInitList().getType()).getPointee());
if (resultType.getMembers().size() != 2)
return emitOpError(
"std::initializer_list must be '!cir.struct' with two fields");
auto memberPtr = mlir::dyn_cast<cir::PointerType>(resultType.getMembers()[0]);
if (memberPtr == nullptr)
return emitOpError("first member type of std::initializer_list must be "
"'!cir.ptr', but provided ")
<< resultType.getMembers()[0];
auto expectedType = memberPtr.getPointee();
for (const mlir::Value &arg : getArgs())
if (expectedType != arg.getType())
return emitOpError("arg type must be ")
<< expectedType << ", but provided " << arg.getType();
return mlir::success();
}

//===----------------------------------------------------------------------===//
// TableGen'd op method definitions
//===----------------------------------------------------------------------===//
Expand Down
83 changes: 1 addition & 82 deletions clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,15 @@
#include "mlir/IR/Region.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/Decl.h"
#include "clang/AST/Mangle.h"
#include "clang/Basic/Module.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/CIR/Dialect/Builder/CIRBaseBuilder.h"
#include "clang/CIR/Dialect/IR/CIRDataLayout.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/Dialect/IR/CIRTypes.h"
#include "clang/CIR/Dialect/Passes.h"
#include "clang/CIR/Interfaces/ASTAttrInterfaces.h"
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
Expand Down Expand Up @@ -89,7 +85,6 @@ struct LoweringPreparePass : public LoweringPrepareBase<LoweringPreparePass> {
void lowerToMemCpy(StoreOp op);
void lowerArrayDtor(ArrayDtor op);
void lowerArrayCtor(ArrayCtor op);
void lowerStdInitializerListOp(StdInitializerListOp op);

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

/// lowering construction of std::initializer_list.
/// 1. alloca array for arg list.
/// 2. copy arg list to array.
/// 3. construct std::initializer_list from array.
void LoweringPreparePass::lowerStdInitializerListOp(StdInitializerListOp op) {
auto loc = op.getLoc();
cir::CIRDataLayout dataLayout(theModule);
auto args = op.getArgs();

auto stdInitializerListType = mlir::cast<cir::StructType>(
mlir::cast<cir::PointerType>(op.getInitList().getType()).getPointee());
clang::RecordDecl::field_range stdInitializerListFields =
stdInitializerListType.getAst().getRawDecl()->fields();

mlir::Type elementType =
mlir::cast<cir::PointerType>(stdInitializerListType.getMembers()[0])
.getPointee();
auto tempArrayType =
cir::ArrayType::get(&getContext(), elementType, args.size());

CIRBaseBuilderTy builder(getContext());
builder.setInsertionPointAfter(op);

IntegerAttr alignment = builder.getI64IntegerAttr(
dataLayout.getPrefTypeAlign(tempArrayType).value());
assert(!cir::MissingFeatures::addressSpace());
mlir::Value arrayPtr = builder.createAlloca(
loc, cir::PointerType::get(tempArrayType), tempArrayType, "", alignment);
mlir::Value arrayStartPtr =
builder.createCast(cir::CastKind::array_to_ptrdecay, arrayPtr,
cir::PointerType::get(elementType));
for (unsigned i = 0; i < args.size(); i++) {
if (i == 0) {
builder.createStore(loc, args[i], arrayStartPtr);
} else {
mlir::Value offset = builder.getUnsignedInt(loc, i, 64);
mlir::Value dest = builder.create<cir::PtrStrideOp>(
loc, arrayStartPtr.getType(), arrayStartPtr, offset);
builder.createStore(loc, args[i], dest);
}
}

// FIXME(cir): better handling according to different field type. [ptr ptr],
// [ptr size], [size ptr].

clang::RecordDecl::field_iterator it = stdInitializerListFields.begin();
const clang::RecordDecl::field_iterator startField = it;
const unsigned startIdx = 0U;
const clang::RecordDecl::field_iterator endOrSizeField = ++it;
const unsigned endOrSizeIdx = 1U;
assert(llvm::range_size(stdInitializerListFields) == 2U);

mlir::Value startMemberPtr = builder.createGetMemberOp(
loc, op.getInitList(), startField->getName().data(), startIdx);
builder.createStore(loc, arrayStartPtr, startMemberPtr);

mlir::Value size = builder.getUnsignedInt(loc, args.size(), 64);
if (endOrSizeField->getType()->isPointerType()) {
mlir::Value arrayEndPtr = builder.create<cir::PtrStrideOp>(
loc, arrayStartPtr.getType(), arrayStartPtr, size);
mlir::Value endMemberPtr = builder.createGetMemberOp(
loc, op.getInitList(), endOrSizeField->getName().data(), endOrSizeIdx);
builder.createStore(loc, arrayEndPtr, endMemberPtr);
} else {
assert(endOrSizeField->getType()->isIntegerType());
mlir::Value sizeMemberPtr = builder.createGetMemberOp(
loc, op.getInitList(), endOrSizeField->getName().data(), endOrSizeIdx);
builder.createStore(loc, size, sizeMemberPtr);
}

op.erase();
}

void LoweringPreparePass::addGlobalAnnotations(mlir::Operation *op,
mlir::ArrayAttr annotations) {
auto globalValue = cast<mlir::SymbolOpInterface>(op);
Expand Down Expand Up @@ -1258,8 +1180,6 @@ void LoweringPreparePass::runOnOp(Operation *op) {
}
if (std::optional<mlir::ArrayAttr> annotations = fnOp.getAnnotations())
addGlobalAnnotations(fnOp, annotations.value());
} else if (auto stdInitializerListOp = dyn_cast<StdInitializerListOp>(op)) {
lowerStdInitializerListOp(stdInitializerListOp);
}
}

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

Expand Down
34 changes: 12 additions & 22 deletions clang/test/CIR/CodeGen/initlist-ptr-ptr.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir -clangir-disable-passes
// RUN: FileCheck --check-prefix=BEFORE --input-file=%t.cir %s
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-llvm -fno-clangir-call-conv-lowering %s -o %t.ll
Expand All @@ -17,16 +15,6 @@ void test() {
}
} // namespace std

// 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>
// BEFORE: %0 = cir.alloca [[INITLIST_TYPE]], !cir.ptr<[[INITLIST_TYPE]]>,
// BEFORE: %1 = cir.get_global @".str" : !cir.ptr<!cir.array<!s8i x 3>>
// BEFORE: %2 = cir.cast(array_to_ptrdecay, %1 : !cir.ptr<!cir.array<!s8i x 3>>), !cir.ptr<!s8i>
// BEFORE: %3 = cir.get_global @".str.1" : !cir.ptr<!cir.array<!s8i x 3>>
// BEFORE: %4 = cir.cast(array_to_ptrdecay, %3 : !cir.ptr<!cir.array<!s8i x 3>>), !cir.ptr<!s8i>
// BEFORE: cir.std.initializer_list %0 (%2, %4 : !cir.ptr<!s8i>, !cir.ptr<!s8i>) : !cir.ptr<[[INITLIST_TYPE]]>
// BEFORE: %5 = cir.load %0 : !cir.ptr<[[INITLIST_TYPE]]>, [[INITLIST_TYPE]]
// BEFORE: cir.call @_ZSt1fIPKcEvSt16initializer_listIT_E(%5) : ([[INITLIST_TYPE]]) -> ()

// CIR: [[INITLIST_TYPE:!.*]] = !cir.struct<class "std::initializer_list<const char *>" {!cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!cir.ptr<!s8i>>}>
// CIR: cir.func linkonce_odr @_ZSt1fIPKcEvSt16initializer_listIT_E(%arg0: [[INITLIST_TYPE]]
// CIR: [[LOCAL:%.*]] = cir.alloca [[INITLIST_TYPE]], !cir.ptr<[[INITLIST_TYPE]]>,
Expand All @@ -39,22 +27,24 @@ void test() {
// CIR: cir.func @_ZSt4testv()
// CIR: cir.scope {
// CIR: [[INITLIST_LOCAL:%.*]] = cir.alloca [[INITLIST_TYPE]], !cir.ptr<[[INITLIST_TYPE]]>,
// CIR: [[LOCAL_ELEM_ARRAY:%.*]] = cir.alloca !cir.array<!cir.ptr<!s8i> x 2>, !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>,
// 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>>
// CIR: [[XY_CHAR_ARRAY:%.*]] = cir.get_global [[STR_XY]] : !cir.ptr<!cir.array<!s8i x 3>>
// CIR: [[STR_XY_PTR:%.*]] = cir.cast(array_to_ptrdecay, [[XY_CHAR_ARRAY]] : !cir.ptr<!cir.array<!s8i x 3>>), !cir.ptr<!s8i>
// CIR: cir.store [[STR_XY_PTR]], [[FIRST_ELEM_PTR]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
// CIR: [[ONE:%.*]] = cir.const #cir.int<1>
// CIR: [[NEXT_ELEM_PTR:%.*]] = cir.ptr_stride([[FIRST_ELEM_PTR]] : !cir.ptr<!cir.ptr<!s8i>>, [[ONE]] : !s64i), !cir.ptr<!cir.ptr<!s8i>>
// CIR: [[UV_CHAR_ARRAY:%.*]] = cir.get_global [[STR_UV]] : !cir.ptr<!cir.array<!s8i x 3>>
// CIR: [[STR_UV_PTR:%.*]] = cir.cast(array_to_ptrdecay, [[UV_CHAR_ARRAY]] : !cir.ptr<!cir.array<!s8i x 3>>), !cir.ptr<!s8i>
// CIR: [[LOCAL_ELEM_ARRAY:%.*]] = cir.alloca !cir.array<!cir.ptr<!s8i> x 2>, !cir.ptr<!cir.array<!cir.ptr<!s8i> x 2>>,
// 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>>
// CIR: cir.store [[STR_XY_PTR]], [[ELEM_BEGIN]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
// CIR: [[ONE:%.*]] = cir.const #cir.int<1>
// CIR: [[NEXT_ELEM_PTR:%.*]] = cir.ptr_stride([[ELEM_BEGIN]] : !cir.ptr<!cir.ptr<!s8i>>, [[ONE]] : !u64i), !cir.ptr<!cir.ptr<!s8i>>
// CIR: cir.store [[STR_UV_PTR]], [[NEXT_ELEM_PTR]] : !cir.ptr<!s8i>, !cir.ptr<!cir.ptr<!s8i>>
// CIR: [[START_FLD_PTR:%.*]] = cir.get_member [[INITLIST_LOCAL]][0] {name = "array_start"} : !cir.ptr<[[INITLIST_TYPE]]> -> !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>
// CIR: cir.store [[ELEM_BEGIN]], [[START_FLD_PTR]] : !cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>
// 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>>>
// 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>>>
// CIR: [[ELEM_ARRAY_LEN:%.*]] = cir.const #cir.int<2>
// CIR: [[ELEM_END:%.*]] = cir.ptr_stride([[ELEM_BEGIN]] : !cir.ptr<!cir.ptr<!s8i>>, [[ELEM_ARRAY_LEN]] : !u64i), !cir.ptr<!cir.ptr<!s8i>>
// CIR: [[END_FLD_PTR:%.*]] = cir.get_member [[INITLIST_LOCAL]][1] {name = "array_end"} : !cir.ptr<[[INITLIST_TYPE]]> -> !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>
// CIR: cir.store [[ELEM_END]], [[END_FLD_PTR]] : !cir.ptr<!cir.ptr<!s8i>>, !cir.ptr<!cir.ptr<!cir.ptr<!s8i>>>
// 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>>
// 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>>>
// 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>>>
// CIR: [[ARG:%.*]] = cir.load [[INITLIST_LOCAL]] : !cir.ptr<[[INITLIST_TYPE]]>, [[INITLIST_TYPE]]
// CIR: cir.call @_ZSt1fIPKcEvSt16initializer_listIT_E([[ARG]]) : ([[INITLIST_TYPE]]) -> ()
// CIR: }
Expand Down Expand Up @@ -82,9 +72,9 @@ void test() {
// LLVM: [[PTR_SECOND_ELEM:%.*]] = getelementptr ptr, ptr [[PTR_FIRST_ELEM]], i64 1
// LLVM: store ptr @.str.1, ptr [[PTR_SECOND_ELEM]], align 8
// LLVM: [[INIT_START_FLD_PTR:%.*]] = getelementptr %"class.std::initializer_list<const char *>", ptr [[INIT_STRUCT]], i32 0, i32 0
// LLVM: store ptr [[PTR_FIRST_ELEM]], ptr [[INIT_START_FLD_PTR]], align 8
// LLVM: [[ELEM_ARRAY_END:%.*]] = getelementptr ptr, ptr [[PTR_FIRST_ELEM]], i64 2
// LLVM: store ptr [[ELEM_ARRAY_PTR]], ptr [[INIT_START_FLD_PTR]], align 8
// LLVM: [[INIT_END_FLD_PTR:%.*]] = getelementptr %"class.std::initializer_list<const char *>", ptr [[INIT_STRUCT]], i32 0, i32 1
// LLVM: [[ELEM_ARRAY_END:%.*]] = getelementptr [2 x ptr], ptr [[ELEM_ARRAY_PTR]], i64 2
// LLVM: store ptr [[ELEM_ARRAY_END]], ptr [[INIT_END_FLD_PTR]], align 8
// LLVM: [[ARG2PASS:%.*]] = load %"class.std::initializer_list<const char *>", ptr [[INIT_STRUCT]], align 8
// LLVM: call void @_ZSt1fIPKcEvSt16initializer_listIT_E(%"class.std::initializer_list<const char *>" [[ARG2PASS]])
Expand Down
Loading
Loading