-
Notifications
You must be signed in to change notification settings - Fork 100
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
implement cir.initlist #1121
base: main
Are you sure you want to change the base?
implement cir.initlist #1121
Conversation
f04fa03
to
90c2cca
Compare
cc @smeenai |
Thanks for looking at this! I think the high-level idea is right here, but I'm wondering if we want to lift up the InitListExpr node instead of the CXXStdInitializerListExpr node. From what I can see in this change, we're still constructing the init list via a sequence of stores, and then have the higher-level op to get an initializer_list from that init list. That's definitely an improvement over the status quo, but having the init list itself be represented directly would be even better. You raised the question of struct vs array inits in #777, and I think we can keep them separate. One other interesting difference is for InitListExprs that directly initialize an array vs. become part of an initializer_list; the former are stored in constant memory and the latter constructed via stores on the stack (https://godbolt.org/z/Ee47xcoaM). Have you looked into what causes that difference? Understanding why the codegen for those two cases differs would help us figure out the appropriate high-level design. |
I agree with you. I will try to re-design
And then "stored in constant memory" or "constructed via stores on the stack" can be determined during the lowering WDYT? |
@smeenai Is this something you describe in origin PR? I don't do store in constant memory when lowering LLVM now but it should be possible. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you! This will be a very nice improvement :)
At a high level, I think we want the op to look like (see also https://llvm.github.io/clangir/Dialect/cir-style-guide.html):
%0 = cir.std_initializer_list %elem1, %elem2, %elem3 : !s32i -> !ty_std3A3Ainitializer_list3Cint3E
It'll probably be simpler to decompose that into lower-level ops inside LoweringPrepare instead of lowering it to LLVM directly.
In the future we may want to lift up other forms of init lists as well, but just tackling std::initializer_list
in this PR is a good starting point (and then we can incrementally build upon that in the future).
@@ -4900,6 +4900,12 @@ def ClearCacheOp : CIR_Op<"clear_cache", [AllTypesMatch<["begin", "end"]>]> { | |||
}]; | |||
} | |||
|
|||
def InitListCtor : CIR_Op<"initlist.ctor"> { | |||
let summary = "Starts a variable argument list"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs updating.
@@ -4900,6 +4900,12 @@ def ClearCacheOp : CIR_Op<"clear_cache", [AllTypesMatch<["begin", "end"]>]> { | |||
}]; | |||
} | |||
|
|||
def InitListCtor : CIR_Op<"initlist.ctor"> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All op names end with Op
, Given that this is specific to std::initializer_list
(and not the generic clang InitListExpr concept, which we may also want to have a higher-level representation for in the future), I think we should also make the name indicate that.
def InitListCtor : CIR_Op<"initlist.ctor"> { | |
def StdInitializerListOp : CIR_Op<"std_initializer_list"> { |
@@ -4900,6 +4900,12 @@ def ClearCacheOp : CIR_Op<"clear_cache", [AllTypesMatch<["begin", "end"]>]> { | |||
}]; | |||
} | |||
|
|||
def InitListCtor : CIR_Op<"initlist.ctor"> { | |||
let summary = "Starts a variable argument list"; | |||
let arguments = (ins CIR_PointerType:$initlist, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be better if the argument was just the arg list, and the op produced a result of the appropriate type. That way you can add the SameTypeOperands
trait to verify that all the operand types are the same. You'll also want to verify that the result type is consistent with the argument type; LoadOp
uses the TypesMatchWith
trait for that, but our logic is a bit more complex, so you might need to implement a custom verifier (https://mlir.llvm.org/docs/DefiningDialects/Operations/#custom-verifier-code).
#endif | ||
mlir::Type llvmArrayType = | ||
mlir::LLVM::LLVMArrayType::get(llvmElementType, argListSize); | ||
mlir::Value llvmArrayPtr = rewriter.create<mlir::LLVM::AllocaOp>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's important for all the allocas
to be at the start of the function, otherwise LLVM will generate worse code.
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