[prev in list] [next in list] [prev in thread] [next in thread]
List: cfe-commits
Subject: [PATCH] D43842: CodeGenObjCXX: handle inalloca appropriately for msgSend variant
From: Reid Kleckner via Phabricator via cfe-commits <cfe-commits () lists ! llvm ! org>
Date: 2018-02-28 21:51:51
Message-ID: c242956c76e89c70ca8d528ebe3d74ac () localhost ! localdomain
[Download RAW message or body]
rnk added a comment.
In https://reviews.llvm.org/D43842#1022546, @rjmccall wrote:
> Okay. In that case, this seems correct, although it seems to me that perhaps \
> `inalloca` is not actually orthogonal to anything else. In fact, it seems to me \
> that maybe `inalloca` ought to just be a bit on the CGFunctionInfo and the \
> individual ABIInfos should be left alone.
I don't think this is a good idea, since when inalloca mixes with `__thiscall` and \
`__fastcall`, register parameters are still passed directly. Consider:
struct S {
S();
S(const S &);
int x;
void thiscall_byval(S o);
};
void S::thiscall_byval(S o) {}
int __fastcall fastcall_byval(int x, int y, S o) { return x + y; }
$ clang -S t.cpp -emit-llvm -m32 -o - | grep define
define dso_local x86_thiscallcc void @"\01?thiscall_byval@S@@QAEXU1@@Z"(%struct.S* \
%this, <{ %struct.S }>* inalloca) #0 align 2 { define dso_local x86_fastcallcc i32 \
@"\01?fastcall_byval@@YIHHHUS@@@Z"(i32 inreg %x, i32 inreg %y, <{ %struct.S }>* \
inalloca) #0 {
So sometimes the sret parameter is not in the inalloca pack:
S __fastcall fastcall_sret(int x, int y, S o) { return o; }
define dso_local x86_fastcallcc void \
@"\01?fastcall_sret@@YI?AUS@@HHU1@@Z"(%struct.S* inreg noalias sret %agg.result, i32 \
inreg %x, <{ i32, %struct.S }>* inalloca)
I think the long term way to clean this up is to use separate allocations for each \
argument, and use tokens to prevent the middle end from messing up the SESE region \
between the argument allocation point and the call that consumes the allocations.
To call foo, the IR would look like:
void foo(int x, S y, int z, S w);
..
foo(1, S(2), 3, S(4));
...
; setup w
%w.token = call token @llvm.allocarg(i32 4)
%w.addr = call %S* @llvm.argaddr(token %w.token)
call void @S_ctor(%S* %w.addr, i32 4)
; setup y
%y.token = call token @llvm.allocarg(i32 4)
%y.addr = call %S* @llvm.argaddr(token %y.token)
call void @S_ctor(%S* %y.addr, i32 2)
; do the call, consume the tokens
call void @foo(i32 1, %S* inalloca %y.addr, i32 3, %S* inalloca %w.addr) \
"allocargs"[token %w.token, token %y.token]
The tokens would make it illegal to tail merge two calls to foo in an if/else diamond \
with PHIs.
It would also mean that all of this Obj-C IRGen code can go back to assuming that \
pointers are passed directly, because now the presence of one non-trivially copyable \
struct doesn't affect the ABIInfo of every other argument.
I am concerned about what happens in evil code like:
foo(({ goto abort_call; 0 }), S(2), 3, S(4));
abort_call:
In this case, control flow breaks out of expression evaluation, and we never \
deallocate the stack memory for the call. We'd need some way to clean that up, \
perhaps with a cleanup.
This would all be a lot easier if LLVM IR had scopes and it wasn't all just basic \
block soup. Just saying.
Repository:
rC Clang
https://reviews.llvm.org/D43842
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic