[cfe-dev] aligned 'new'
Anton Yartsev
anton.yartsev at gmail.com
Tue Dec 6 06:10:18 PST 2011
Updated the patch.
Please review!
>> Here is an updated patch with lots of changes. Tried to make it of
>> higher quality. Please review.
>>
>> aligned_new_test.cpp - new test from clang\test\CodeGenCXX\
>> aligned_new.h - header with new declarations from clang\lib\Headers\
>> HelperLibs.zip - files for creating library. Placed it to clang\lib\
>>
>>>> Putting this functions to clang header makes the feature
>>>> independent of library used
>>> Yes, but it has several unfortunate side effects:
>>>
>>> (1) We'll end up with copies of these functions in every .o file
>>> that uses new or delete, which is likely to cause some serious code
>>> bloat
>>> (2) Unlike with the default new/new[]/delete/delete[] operators
>>> provided by the C++ implementation, these 'aligned' versions are not
>>> replaceable by the user because their definitions are internal to
>>> each .o file
>>>
>>> There are other ways to achieve library independence. For example,
>>> the definitions could be in a separate library that we link against
>>> when -fstrict-aligned is provided, and the declarations themselves
>>> could be synthesized by the compiler when needed (e.g., as a library
>>> built-in).
>> Made standard non-placement declarations synthesized by the compiler
>> as it is made for standard non-placement new/new[]/delete/delete[].
>> Moved the definitions to separate library
>>>
>>>>> @@ -1282,10 +1354,54 @@
>>>>>
>>>>> // Didn't find a member overload. Look for a global one.
>>>>> DeclareGlobalNewDelete();
>>>>> DeclContext *TUDecl = Context.getTranslationUnitDecl();
>>>>> +
>>>>> if (FindAllocationOverload(StartLoc, Range,
>>>>> NewName,&AllocArgs[0],
>>>>> AllocArgs.size(), TUDecl,
>>>>> /*AllowMissing=*/false,
>>>>> OperatorNew))
>>>>> return true;
>>>>> +
>>>>> + // replace calls to allocation functions defined in
>>>>> the<new> header
>>>>> + // with calls to its aligned analogs
>>>>> + if (getLangOptions().StrictAligned&&
>>>>> + isDefaultLibraryAllocationFunction(OperatorNew)) {
>>>>> +
>>>>> + OperatorNew = 0;
>>>>> +
>>>>> + DeclarationName AlignedNewName(
>>>>> +&Context.Idents.get(IsArray ? "__aligned_new_arr" :
>>>>> "__aligned_new"));
>>>>> +
>>>>> + DeclarationName AlignedDeleteName(
>>>>> +&Context.Idents.get(IsArray ? "__aligned_delete_arr"
>>>>> + : "__aligned_delete"));
>>>>> +
>>>>> + // construct additional parameter - alignment
>>>>> + IntegerLiteral AlignmentArg(Context,
>>>>> llvm::APInt::getNullValue(
>>>>> +
>>>>> Context.Target.getPointerWidth(0)),
>>>>> + Context.getSizeType(),
>>>>> + SourceLocation());
>>>>> +
>>>>> + llvm::SmallVector<Expr*, 8> ArgsPlusAlign(AllocArgs);
>>>>> +
>>>>> + // insert alignment parameter just after the Size parameter
>>>>> + ArgsPlusAlign.insert(ArgsPlusAlign.begin()+1,&AlignmentArg);
>>>>> +
>>>>> + if (FindAllocationOverload(StartLoc, Range, AlignedNewName,
>>>>> +&ArgsPlusAlign[0], ArgsPlusAlign.size(), TUDecl,
>>>>> + /*AllowMissing=*/false,
>>>>> OperatorNew))
>>>>> + return true;
>>>>>
>>>>> There's no fallback here, which seems to imply that if the call to
>>>>> __aligned_new/__aligned_new_arr/etc. fails, we won't end up trying
>>>>> to the standard-mandated operator new/operator new[]/etc. Is that
>>>>> really the intended behavior? It seems like fairly significant
>>>>> breakage to me.
>>>> If the call to __aligned_... fails we end up with an error ('no
>>>> matching function for call to ...'). This behavior seem correct to
>>>> me as specifying -fstrict-aligned option we expect our data to be
>>>> aligned properly.
>>> Does this actually break existing C++ code that overloads operators
>>> new/new[]/delete/delete[], or am I missing something? If it does
>>> break code, is that "by design" or "by accident"?
>> No, calls to standard new/new[]/delete/delete[], either replaced or
>> not, will be substituted, calls to overloaded
>> new/new[]/delete/delete[] will remain unchanged. Calls to
>> new/new[]/delete/delete[] declared in the class scope remain
>> unchanged regardless of the signature.
>>
>>>> That is how the feature is designed in ppu-lv2-gcc:
>>>> giving -fstrict-align option to ppu-lv2-gcc does the following:
>>>> 1) It cause ppu-lv2-gcc to define the built-in macro
>>>> "__STRICT_ALIGNED".
>>>> 2) The PS3 header "new" has some new declarations for new and
>>>> delete operators (standard, nothrow and placement, both simple and
>>>> array versions) that take an additional size_t parameter for
>>>> alignment. These are conditionalized on the __STRICT_ALIGNED flag.
>>> If the PS3 header<new> has the declarations of the aligned
>>> new/delete operators now, why is your patch adding these operators
>>> to Clang's mm_alloc.h? Isn't the precedent already there to make
>>> sure<new> has these declarations, which is most likely the better
>>> answer?
>> I want the declarations live in the <new> header, but I want the
>> feature be independent of the library. Adding <new> header to clang
>> leads to ambiguity. Moved the declarations temporarily to separate
>> header aligned_new.h. It will not be included often as standard
>> non-placement declarations are now synthesized by clang. I can make
>> the rest of the declarations also be synthesized and then there will
>> be no need to include aligned_new.h at all
>>>> 3) If this option is set, when ppu-lv2-gcc sees a new or delete of
>>>> a type which either has an inherent alignment, or has an explicit
>>>> alignment specified by __attribute__((__aligned__(x))), it will
>>>> transform the standard new or delete call to a call to the aligned
>>>> version of new or delete.
>>> Every type has alignment, so you're saying that every "standard"
>>> new/delete/new[]/delete[] expression calls into the aligned version
>>> of new/delete/new[]/delete[]. And you're only talking about the
>>> global operators new/delete/new[]/delete[] that have one of the
>>> forms described in<new>; this replacement doesn't apply for
>>> operators with different signatures from those in<new> or for those
>>> operators when they're defined at class scope. Is the omission of
>>> support for allocation/deallocation functions at class scope
>>> intentional? If so, the compiler should emit an error if someone
>>> does write one of these operators at class scope, because they're
>>> useless (and accepting them is misleading). If not, then we're
>>> missing code to support that case.
>> Calls to new/new[]/delete/delete[] declared in the class scope are
>> all left unchanged. No errors or warnings are generated. That is how
>> ppu-lv2-gcc does. Do you want me to change the behavior?
>>>
>>> Some more detailed comments to follow, but I'm having a lot of
>>> trouble with this feature. I understand that the design of the
>>> feature is not really up for debate, because we're implementing an
>>> extension that was defined by another compiler, and I can live with
>>> that. That said, we need to have a specification of this feature
>>> that users and compiler writers alike can use to understand how this
>>> feature is supposed to work, because we don't all have access to a
>>> copy of ppu-lv2-gcc to act as an oracle for how this feature
>>> behaves. The specification needs to go into Clang's language
>>> extensions page, so people know it is there and usable:
>>>
>>> http://clang.llvm.org/docs/LanguageExtensions.html
>> Updated LanguageExtensions.html
>>>
>>> Now, for the minor comments:
>>>
>>> Index: include/clang/Basic/LangOptions.h
>>> ===================================================================
>>> --- include/clang/Basic/LangOptions.h (revision 138994)
>>> +++ include/clang/Basic/LangOptions.h (working copy)
>>> @@ -140,6 +140,8 @@
>>>
>>> unsigned MRTD : 1; // -mrtd calling convention
>>> unsigned DelayedTemplateParsing : 1; // Delayed template parsing
>>>
>>> + unsigned StrictAligned : 1; // Enforce aligned attribute with
>>> 'operator new'
>>> +
>>> private:
>>> // We declare multibit enums as unsigned because MSVC insists on
>>> making enums
>>> // signed. Set/Query these values using accessors.
>>>
>>> Every LangOptions flag needs to be serialized/de-serialized and
>>> checked by the ASTWriter and ASTReader.
>>>
>>> Also, StrictAligned needs to be initialized.
>> Done
>>>
>>> Index: include/clang/Driver/CC1Options.td
>>> ===================================================================
>>> --- include/clang/Driver/CC1Options.td (revision 138994)
>>> +++ include/clang/Driver/CC1Options.td (working copy)
>>> @@ -433,6 +433,8 @@
>>>
>>> HelpText<"Disable implicit builtin knowledge of functions">;
>>> def faltivec : Flag<"-faltivec">,
>>> HelpText<"Enable AltiVec vector initializer syntax">;
>>> +def fstrict_aligned : Flag<"-fstrict-aligned">,
>>> + HelpText<"Enforce aligned attribute with 'operator new'">;
>>> def fno_access_control : Flag<"-fno-access-control">,
>>> HelpText<"Disable C++ access control">;
>>> def fno_assume_sane_operator_new :
>>> Flag<"-fno-assume-sane-operator-new">,
>>>
>>> This is a -cc1-level flag. I assume that you also want it to work in
>>> the Clang driver? You'll need to update the driver, too.
>> Done
>>>
>>> Index: lib/AST/Decl.cpp
>>> ===================================================================
>>> --- lib/AST/Decl.cpp (revision 138994)
>>> +++ lib/AST/Decl.cpp (working copy)
>>> @@ -1533,7 +1533,31 @@
>>>
>>> getIdentifier()->isStr("main");
>>> }
>>>
>>> +bool FunctionDecl::isAlignedSubstitutionOfNewDelete(bool CheckNew,
>>> + bool CheckNewArr,
>>> + bool CheckDelete,
>>> + bool
>>> CheckDeleteArr) const {
>>> +
>>> + if (!getASTContext().getLangOptions().StrictAligned)
>>> + return false;
>>> +
>>> + IdentifierInfo *II = getDeclName().getAsIdentifierInfo();
>>> +
>>> + return (II&& ((CheckNew&& II->isStr("__aligned_new")) ||
>>> + (CheckNewArr&& II->isStr("__aligned_new_arr")) ||
>>> + (CheckDelete&& II->isStr("__aligned_delete")) ||
>>> + (CheckDeleteArr&&
>>> II->isStr("__aligned_delete_arr"))));
>>> +}
>>>
>>> isStr() is inefficient. You'll need to cache the IdentifierInfos for
>>> these four strings and perform pointer comparisons against II.
>>>
>>> I also find this API to be a bit strangeā¦ why not call this
>>> classifyAlignedSubstitutionOfNewDelete() and return a value of
>>> enumeration type that tells us which one it is?
>> Done
>>>
>>> bool FunctionDecl::isReservedGlobalPlacementOperator() const {
>>> +
>>> + // calls to new/delete were substituted by calls to it's aligned
>>> analogs
>>> + if (isAlignedSubstitutionOfNewDelete(
>>> + /*new*/true, /*new[]*/true, /*delete*/true, /*delete[]*/true))
>>> + return false;
>>> + //FIXME: maybe add logic for detecting aligned analogs of
>>> reserved global
>>> + // placement operators
>>>
>>> Why is this isAlignedSubstitutionOfNewDelete check even necessary?
>>> If you're changing the contract of
>>> FunctionDecl::isReservedGlobalPlacementOperator() to allow functions
>>> whose name isn't a C++ new/delete/new[]/delete[] operator, that's
>>> fine, but just return false if
>> Done
>>>
>>> getDeclName().getNameKind() != DeclarationName::CXXOperatorName
>>>
>>> @@ -1836,6 +1839,9 @@
>>> else
>>> Opts.ObjCXXARCStandardLibrary =
>>> (ObjCXXARCStandardLibraryKind)Library;
>>> }
>>> +
>>> + if(Args.hasArg(OPT_fstrict_aligned))
>>> + Opts.Includes.push_back("mm_malloc.h");
>>> }
>>>
>>> Architecturally, I'm strongly opposed to auto-including headers like
>>> this. Either the user should have to include a header manually
>>> (e.g.,<new>) or the compiler should synthesize the declarations it
>>> needs on demand.
>> Done
>>
--
Anton
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: aligned_new.h
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20111206/ff400180/attachment.h>
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: aligned_new_test.cpp
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20111206/ff400180/attachment.ksh>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: aligned_new_v1.1.patch
Type: text/x-diff
Size: 28411 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20111206/ff400180/attachment.patch>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: HelperLibs.zip
Type: application/x-zip-compressed
Size: 3913 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20111206/ff400180/attachment.bin>
More information about the cfe-dev
mailing list