Re: How to access the function body of a constructor?
This post is in continuation to my below post. My pass is hooked after pass_ipa_pta as already mentioned below. I have enabled the LTO framework by using the flags "-flto -flto-partition=none". Without the LTO mode, macro DECL_CLONED_FUNCTION returns the cloned constructor. However, in the LTO mode this information is not available. How do I make this information available in the LTO framework? Is there any other way to get the cloned copy of the constructor "__base_ctor" from "__comp_ctor"? Regards, Swati On Monday 15 September 2014 03:41 PM, Swati Rathi wrote: I am trying to access the body of a constructor. My pass is hooked after pass_ipa_pta. Constructor for a class is invoked as : __comp_ctor (&b); However the constructor body is dumped as __base_ctor (struct B * const this) { : } I am not able to access basic blocks from __comp_ctor? Is __comp_ctor a cloned function of __base_ctor? Also assuming it to be a cloned function, I tried to access it using "clones", "clones_of" fields of structure cgraph_node. But these fields does not store anything (or at least for the functions I tried). What does these fields (clones, clone_of etc.) store? Will the macro DECL_CLONED_FUNCTION give me __base_ctor from __comp_ctor ? I tried using it but it gives an error, "undefined symbol: _Z22decl_cloned_function_pPK9tree_nodeb". Kindly tell me way to access the constructor body. Regards, Swati
Re: [gimple-classes, committed 4/6] tree-ssa-tail-merge.c: Use gassign
On Fri, Nov 07, 2014 at 10:01:45PM +0100, Richard Biener wrote: > Just a comment as these patches flow by - I think this is a huge step > backwards from "enforcing" s1/s2 being a gimple_assign inside > gimple_assign_rhs1 to this as_a boilerplate at _each_ callsite! FWIW, I feel the same way. More to type, worse readability, a lot more of line-wrapping. Sorry, Marek
Re: [gimple-classes, committed 4/6] tree-ssa-tail-merge.c: Use gassign
On Fri, Nov 7, 2014 at 10:01 PM, Richard Biener wrote: > On Fri, Nov 7, 2014 at 4:21 PM, David Malcolm wrote: >> gcc/ChangeLog.gimple-classes: >> * tree-ssa-tail-merge.c (same_succ_hash): Add checked cast. >> (gimple_equal_p): Add checked casts. >> --- >> gcc/ChangeLog.gimple-classes | 5 + >> gcc/tree-ssa-tail-merge.c| 8 +--- >> 2 files changed, 10 insertions(+), 3 deletions(-) >> >> diff --git a/gcc/ChangeLog.gimple-classes b/gcc/ChangeLog.gimple-classes >> index f43df63..0bd0421 100644 >> --- a/gcc/ChangeLog.gimple-classes >> +++ b/gcc/ChangeLog.gimple-classes >> @@ -1,5 +1,10 @@ >> 2014-11-06 David Malcolm >> >> + * tree-ssa-tail-merge.c (same_succ_hash): Add checked cast. >> + (gimple_equal_p): Add checked casts. >> + >> +2014-11-06 David Malcolm >> + >> * tree-ssa-structalias.c (find_func_aliases): Replace >> is_gimple_assign with a dyn_cast, introducing local gassign * >> "t_assign", using it in place of "t" for typesafety. >> diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c >> index 5678657..b822214 100644 >> --- a/gcc/tree-ssa-tail-merge.c >> +++ b/gcc/tree-ssa-tail-merge.c >> @@ -484,7 +484,7 @@ same_succ_hash (const_same_succ e) >> >>hstate.add_int (gimple_code (stmt)); >>if (is_gimple_assign (stmt)) >> - hstate.add_int (gimple_assign_rhs_code (stmt)); >> + hstate.add_int (gimple_assign_rhs_code (as_a (stmt))); >>if (!is_gimple_call (stmt)) >> continue; >>if (gimple_call_internal_p (stmt)) >> @@ -1172,8 +1172,10 @@ gimple_equal_p (same_succ same_succ, gimple s1, >> gimple s2) >>if (TREE_CODE (lhs1) != SSA_NAME >> && TREE_CODE (lhs2) != SSA_NAME) >> return (operand_equal_p (lhs1, lhs2, 0) >> - && gimple_operand_equal_value_p (gimple_assign_rhs1 (s1), >> -gimple_assign_rhs1 (s2))); >> + && gimple_operand_equal_value_p (gimple_assign_rhs1 ( >> + as_a (s1)), >> +gimple_assign_rhs1 ( >> + as_a (s2; > > Just a comment as these patches flow by - I think this is a huge step > backwards from "enforcing" s1/s2 being a gimple_assign inside > gimple_assign_rhs1 to this as_a boilerplate at _each_ callsite! > > Which means this step of the refactoring is totally broken and probably > requires much more manual work to avoid this kind of uglyness. > > I definitely won't approve of this kind of changes. To be constructive here - the above case is from within a GIMPLE_ASSIGN case label and thus I'd have expected case GIMPLE_ASSIGN: { gassign *a1 = as_a (s1); gassign *a2 = as_a (s2); lhs1 = gimple_assign_lhs (a1); lhs2 = gimple_assign_lhs (a2); if (TREE_CODE (lhs1) != SSA_NAME && TREE_CODE (lhs2) != SSA_NAME) return (operand_equal_p (lhs1, lhs2, 0) && gimple_operand_equal_value_p (gimple_assign_rhs1 (a1), gimple_assign_rhs1 (a2))); else if (TREE_CODE (lhs1) == SSA_NAME && TREE_CODE (lhs2) == SSA_NAME) return vn_valueize (lhs1) == vn_valueize (lhs2); return false; } instead. That's the kind of changes I have expected and have approved of. Thanks, Richard. > Thanks, > Richard. > >>else if (TREE_CODE (lhs1) == SSA_NAME >>&& TREE_CODE (lhs2) == SSA_NAME) >> return vn_valueize (lhs1) == vn_valueize (lhs2); >> -- >> 1.7.11.7 >>
Re: [gimple-classes, committed 4/6] tree-ssa-tail-merge.c: Use gassign
On Sat, Nov 08, 2014 at 01:07:28PM +0100, Richard Biener wrote: > To be constructive here - the above case is from within a > GIMPLE_ASSIGN case label > and thus I'd have expected > > case GIMPLE_ASSIGN: > { > gassign *a1 = as_a (s1); > gassign *a2 = as_a (s2); > lhs1 = gimple_assign_lhs (a1); > lhs2 = gimple_assign_lhs (a2); > if (TREE_CODE (lhs1) != SSA_NAME > && TREE_CODE (lhs2) != SSA_NAME) > return (operand_equal_p (lhs1, lhs2, 0) > && gimple_operand_equal_value_p (gimple_assign_rhs1 (a1), > gimple_assign_rhs1 (a2))); > else if (TREE_CODE (lhs1) == SSA_NAME >&& TREE_CODE (lhs2) == SSA_NAME) > return vn_valueize (lhs1) == vn_valueize (lhs2); > return false; > } > > instead. That's the kind of changes I have expected and have approved of. But even that looks like just adding extra work for all developers, with no gain. You only have to add extra code and extra temporaries, in switches typically also have to add {} because of the temporaries and thus extra indentation level, and it doesn't simplify anything in the code. Jakub
Re: [gimple-classes, committed 4/6] tree-ssa-tail-merge.c: Use gassign
On Sat, 2014-11-08 at 13:07 +0100, Richard Biener wrote: > On Fri, Nov 7, 2014 at 10:01 PM, Richard Biener > wrote: > > On Fri, Nov 7, 2014 at 4:21 PM, David Malcolm wrote: > >> gcc/ChangeLog.gimple-classes: > >> * tree-ssa-tail-merge.c (same_succ_hash): Add checked cast. > >> (gimple_equal_p): Add checked casts. > >> --- > >> gcc/ChangeLog.gimple-classes | 5 + > >> gcc/tree-ssa-tail-merge.c| 8 +--- > >> 2 files changed, 10 insertions(+), 3 deletions(-) > >> > >> diff --git a/gcc/ChangeLog.gimple-classes b/gcc/ChangeLog.gimple-classes > >> index f43df63..0bd0421 100644 > >> --- a/gcc/ChangeLog.gimple-classes > >> +++ b/gcc/ChangeLog.gimple-classes > >> @@ -1,5 +1,10 @@ > >> 2014-11-06 David Malcolm > >> > >> + * tree-ssa-tail-merge.c (same_succ_hash): Add checked cast. > >> + (gimple_equal_p): Add checked casts. > >> + > >> +2014-11-06 David Malcolm > >> + > >> * tree-ssa-structalias.c (find_func_aliases): Replace > >> is_gimple_assign with a dyn_cast, introducing local gassign * > >> "t_assign", using it in place of "t" for typesafety. > >> diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c > >> index 5678657..b822214 100644 > >> --- a/gcc/tree-ssa-tail-merge.c > >> +++ b/gcc/tree-ssa-tail-merge.c > >> @@ -484,7 +484,7 @@ same_succ_hash (const_same_succ e) > >> > >>hstate.add_int (gimple_code (stmt)); > >>if (is_gimple_assign (stmt)) > >> - hstate.add_int (gimple_assign_rhs_code (stmt)); > >> + hstate.add_int (gimple_assign_rhs_code (as_a (stmt))); > >>if (!is_gimple_call (stmt)) > >> continue; > >>if (gimple_call_internal_p (stmt)) > >> @@ -1172,8 +1172,10 @@ gimple_equal_p (same_succ same_succ, gimple s1, > >> gimple s2) > >>if (TREE_CODE (lhs1) != SSA_NAME > >> && TREE_CODE (lhs2) != SSA_NAME) > >> return (operand_equal_p (lhs1, lhs2, 0) > >> - && gimple_operand_equal_value_p (gimple_assign_rhs1 (s1), > >> -gimple_assign_rhs1 (s2))); > >> + && gimple_operand_equal_value_p (gimple_assign_rhs1 ( > >> + as_a (s1)), > >> +gimple_assign_rhs1 ( > >> + as_a > >> (s2; > > > > Just a comment as these patches flow by - I think this is a huge step > > backwards from "enforcing" s1/s2 being a gimple_assign inside > > gimple_assign_rhs1 to this as_a boilerplate at _each_ callsite! > > > > Which means this step of the refactoring is totally broken and probably > > requires much more manual work to avoid this kind of uglyness. > > > > I definitely won't approve of this kind of changes. > > To be constructive here - the above case is from within a > GIMPLE_ASSIGN case label > and thus I'd have expected > > case GIMPLE_ASSIGN: > { > gassign *a1 = as_a (s1); > gassign *a2 = as_a (s2); > lhs1 = gimple_assign_lhs (a1); > lhs2 = gimple_assign_lhs (a2); > if (TREE_CODE (lhs1) != SSA_NAME > && TREE_CODE (lhs2) != SSA_NAME) > return (operand_equal_p (lhs1, lhs2, 0) > && gimple_operand_equal_value_p (gimple_assign_rhs1 (a1), > gimple_assign_rhs1 (a2))); > else if (TREE_CODE (lhs1) == SSA_NAME >&& TREE_CODE (lhs2) == SSA_NAME) > return vn_valueize (lhs1) == vn_valueize (lhs2); > return false; > } > > instead. That's the kind of changes I have expected and have approved of. I do make the above kind of change in some places within the gimple-classes branch. I think I didn't do it in this case because the body of the "case GIMPLE_ASSIGN" doesn't yet have braces, so adding locals requires adding them and re-indenting the case body. I didn't spot the opportunity to speed up the code as you do above by converting the two gimple_get_lhs to gimple_assign_lhs. Without that, I guess I decided to simply add the two as_a<> directly in-place to avoid the reindent. With your speedup it's clearly better to reindent the code. (Got to go now, sorry; I hope to write a better reply on Monday) Thanks Dave
Re: mt_allocator.cc assumes sizeof(size_t) == sizeof(void *)
On 7 November 2014 16:56, Joel Sherrill wrote: > > On 11/7/2014 9:25 AM, Paolo Carlini wrote: >> Hi, >> >> On 11/07/2014 04:07 PM, Joel Sherrill wrote: >>> Hi >>> >>> On m32c-rtems, we have a build error in C++ because size_t >>> is 16-bits and pointers are 24 bits. m32c-elf probably does not >>> enable __GTHREAD support like rtems does. Since this is code >>> shared across targets, what is the best way to fix this? >> I don't know the exact opinion of the other library maintainers, but >> personally I consider mt_allocator an old experiment, which, definitely, >> to make any sense today would need profound changes. In particular, I >> don't think we can hope to get something useful from it when size_t is >> 16 bits and, more importantly, pointers are 24 bits. Thus, my >> recommendation would be just arranging for its code not to break >> bootstrap, nothing more than that. Agreed. > OK. I am building now with the size_t changed to uintptr_t. I tried to get > the type definition by including but it didn't compile. Did you try std::uintptr_t?
Re: mt_allocator.cc assumes sizeof(size_t) == sizeof(void *)
On November 8, 2014 9:00:02 AM CST, Jonathan Wakely wrote: >On 7 November 2014 16:56, Joel Sherrill wrote: >> >> On 11/7/2014 9:25 AM, Paolo Carlini wrote: >>> Hi, >>> >>> On 11/07/2014 04:07 PM, Joel Sherrill wrote: Hi On m32c-rtems, we have a build error in C++ because size_t is 16-bits and pointers are 24 bits. m32c-elf probably does not enable __GTHREAD support like rtems does. Since this is code shared across targets, what is the best way to fix this? >>> I don't know the exact opinion of the other library maintainers, but >>> personally I consider mt_allocator an old experiment, which, >definitely, >>> to make any sense today would need profound changes. In particular, >I >>> don't think we can hope to get something useful from it when size_t >is >>> 16 bits and, more importantly, pointers are 24 bits. Thus, my >>> recommendation would be just arranging for its code not to break >>> bootstrap, nothing more than that. > >Agreed. > >> OK. I am building now with the size_t changed to uintptr_t. I tried >to get >> the type definition by including but it didn't compile. > >Did you try std::uintptr_t? Yes. The only surprise was needing to include stdint.h instead of cstdint to get uintptr_t. It built m32c-rtems and then I left a native Linux bootstrap and make check running. I will post the test results and patch Monday. Hopefully that is an OK solution. --joel
Re: mt_allocator.cc assumes sizeof(size_t) == sizeof(void *)
On November 8, 2014 9:00:02 AM CST, Jonathan Wakely wrote: >On 7 November 2014 16:56, Joel Sherrill wrote: >> >> On 11/7/2014 9:25 AM, Paolo Carlini wrote: >>> Hi, >>> >>> On 11/07/2014 04:07 PM, Joel Sherrill wrote: Hi On m32c-rtems, we have a build error in C++ because size_t is 16-bits and pointers are 24 bits. m32c-elf probably does not enable __GTHREAD support like rtems does. Since this is code shared across targets, what is the best way to fix this? >>> I don't know the exact opinion of the other library maintainers, but >>> personally I consider mt_allocator an old experiment, which, >definitely, >>> to make any sense today would need profound changes. In particular, >I >>> don't think we can hope to get something useful from it when size_t >is >>> 16 bits and, more importantly, pointers are 24 bits. Thus, my >>> recommendation would be just arranging for its code not to break >>> bootstrap, nothing more than that. > >Agreed. > >> OK. I am building now with the size_t changed to uintptr_t. I tried >to get >> the type definition by including but it didn't compile. > >Did you try std::uintptr_t? Doh!! You meant putting std:: in front and using cstdint. No. I will try that. Sorry for missing the point.
Re: mt_allocator.cc assumes sizeof(size_t) == sizeof(void *)
On November 8, 2014 9:04:14 AM CST, Joel Sherrill wrote: > > >On November 8, 2014 9:00:02 AM CST, Jonathan Wakely > wrote: >>On 7 November 2014 16:56, Joel Sherrill wrote: >>> >>> On 11/7/2014 9:25 AM, Paolo Carlini wrote: Hi, On 11/07/2014 04:07 PM, Joel Sherrill wrote: > Hi > > On m32c-rtems, we have a build error in C++ because size_t > is 16-bits and pointers are 24 bits. m32c-elf probably does not > enable __GTHREAD support like rtems does. Since this is code > shared across targets, what is the best way to fix this? I don't know the exact opinion of the other library maintainers, >but personally I consider mt_allocator an old experiment, which, >>definitely, to make any sense today would need profound changes. In particular, >>I don't think we can hope to get something useful from it when size_t >>is 16 bits and, more importantly, pointers are 24 bits. Thus, my recommendation would be just arranging for its code not to break bootstrap, nothing more than that. >> >>Agreed. >> >>> OK. I am building now with the size_t changed to uintptr_t. I tried >>to get >>> the type definition by including but it didn't compile. >> >>Did you try std::uintptr_t? > >Doh!! You meant putting std:: in front and using cstdint. No. I will >try that. This didn't compile. Ended with an error about requiring C++11 in a header file. This code is in a c++98 subdirectory so it dues make sense. I can't cut and paste it at home. >Sorry for missing the point.
Re: mt_allocator.cc assumes sizeof(size_t) == sizeof(void *)
On 8 November 2014 15:30, Joel Sherrill wrote: > This didn't compile. Ended with an error about requiring C++11 in a header > file. This code is in a c++98 subdirectory so it dues make sense. I can't cut > and paste it at home. Yep, that makes sense, I'd just stick with stdint.h
More useful support for low-end ARM architecture
Hello gcc folks, recently I started to expand a project of mine running mainly on AVR ATmega to low end ARM chips. To my enlightment, gcc supports these thingies already. To my disappointment, this support is pretty complicated. One faces at least a much steeper learning curve that on AVR. Accordingly I suggested on the avr-libc mailing list to do similar work for ARM, Cortex-M0 to Cortex-M4. At least four people expressed interest, it looks like arm-libc is about to be born. To those not knowing what this is, I talk here about all-in-one CPUs (MCUs) with memory and some peripherals already on the chip. Program memory can be as low as 8 kB, RAM as low as 1 kB. Usually they're programmed bare-metal, this is, without any operating system. If you want to take a look at a simple Hello World application, here is one: https://bugs.launchpad.net/gcc-arm-embedded/+bug/1387906 Looking at its Makefile, it requires quite a number of flags, among them nine -I with custom paths, --specs, -T and also auto-generated C files. Lots of stuff average programmers probably don't even know it exists. One of the interested persons on the avr-libc mailing list explained what's missing, much better than I could: > I think what the other responders missed is that avr-libc (via its > integration with binutils and gcc) gives you two key pieces of > functionality: > > -mmcu=atmega88 > #include > > You *also* get classic libc functionality (printf, etc) that's provided > on ARM by newlib etc, but that's not the big deal IMO. > > The #include is *relatively* easy, [... no topic for gcc ...] > > The -mmcu= functionality is even more deeply useful, although less > easily repeatable on ARM. It brings in the relevant linker script, > startup code, vector tables, and all the other infrastructure. *THAT* > is what makes it possible to write a program like: > > #include > int main() { > DDRD = 0x01;PORTD = 0x01; > } > > # avr-gcc -mmcu=atmega88 -o test test.c > # avrdude > > Writing a program for your random ARM chip requires digging *deeply* > into the various websites or IDEs of the manufacturer, trying to find > the right files (the filenames alone of which vary in strange ways), > probably determining the right way to alter them because the only > example you found was for a different chip in the same line, and then > hoping you've got everything glued together properly. > > I want to be able to write the above program (modified for the right > GPIO) and run: > > # arm-none-eabi-gcc -mmcu=stm32f405 -o test test.c This is why I joined here, we'd like to get -mmcu for all the ARM flavours. It should pick up a linker script which works in most cases on its own. It should also bring in startup code, so code writers don't have to mess with stuff happening before main(). And not to forget, pre-set #defines like __ARM_LPC1114__, __ARM_STM32F405__, etc. - How would we proceed in general? - Many flavours at once, or better start with one or two, adding more when these work? - Did AVR support make things we should not repeat? Thanks for discussing, Markus P.S.: arm-libc discussion so far can be followed here: http://lists.nongnu.org/archive/html/avr-libc-dev/2014-11/threads.html -- - - - - - - - - - - - - - - - - - - - Dipl. Ing. (FH) Markus Hitter http://www.jump-ing.de/
Re: RFC: Update ISL under gcc/infrastructure/ ? // Remove CLooG?
> Sounds good as long as they will compile and pass tests independently. > Please also remember updating the documentation. I’m trying to build Graphite without CLooG, but I get the following error: libbackend.a(graphite-optimize-isl.o): In function `getScheduleForBandList': /home/roman/sec_trunk/gcc/gcc/graphite-optimize-isl.c:357: undefined reference to `isl_band_member_is_zero_distance' collect2: error: ld returned 1 exit status make[3]: *** [lto1] Error 1 make[3]: *** Waiting for unfinished jobs libbackend.a(graphite-optimize-isl.o): In function `getScheduleForBandList': /home/roman/sec_trunk/gcc/gcc/graphite-optimize-isl.c:357: undefined reference to `isl_band_member_is_zero_distance' collect2: error: ld returned 1 exit status make[3]: *** [cc1] Error 1 libbackend.a(graphite-optimize-isl.o): In function `getScheduleForBandList': /home/roman/sec_trunk/gcc/gcc/graphite-optimize-isl.c:357: undefined reference to `isl_band_member_is_zero_distance' collect2: error: ld returned 1 exit status make[3]: *** [cc1plus] Error 1 rm gcov-tool.pod gfdl.pod fsf-funding.pod gcc.pod cpp.pod gcov.pod make[3]: Leaving directory `/home/roman/compiled/build_graphite_sec/gcc' make[2]: *** [all-stage1-gcc] Error 2 make[2]: Leaving directory `/home/roman/compiled/build_graphite_sec' make[1]: *** [stage1-bubble] Error 2 make[1]: Leaving directory `/home/roman/compiled/build_graphite_sec' make: *** [all] Error 2 Could you please advise me how to fix this? If I’m not mistaken, r216735 is the only commit related to graphite-optimize-isl.c which has been made since my latest patch. -- Cheers, Roman Gareev.
Re: RFC: Update ISL under gcc/infrastructure/ ? // Remove CLooG?
On 08.11.2014 20:49, Roman Gareev wrote: Sounds good as long as they will compile and pass tests independently. Please also remember updating the documentation. I’m trying to build Graphite without CLooG, but I get the following error: libbackend.a(graphite-optimize-isl.o): In function `getScheduleForBandList': /home/roman/sec_trunk/gcc/gcc/graphite-optimize-isl.c:357: undefined reference to `isl_band_member_is_zero_distance' collect2: error: ld returned 1 exit status make[3]: *** [lto1] Error 1 make[3]: *** Waiting for unfinished jobs libbackend.a(graphite-optimize-isl.o): In function `getScheduleForBandList': /home/roman/sec_trunk/gcc/gcc/graphite-optimize-isl.c:357: undefined reference to `isl_band_member_is_zero_distance' collect2: error: ld returned 1 exit status make[3]: *** [cc1] Error 1 libbackend.a(graphite-optimize-isl.o): In function `getScheduleForBandList': /home/roman/sec_trunk/gcc/gcc/graphite-optimize-isl.c:357: undefined reference to `isl_band_member_is_zero_distance' collect2: error: ld returned 1 exit status make[3]: *** [cc1plus] Error 1 rm gcov-tool.pod gfdl.pod fsf-funding.pod gcc.pod cpp.pod gcov.pod make[3]: Leaving directory `/home/roman/compiled/build_graphite_sec/gcc' make[2]: *** [all-stage1-gcc] Error 2 make[2]: Leaving directory `/home/roman/compiled/build_graphite_sec' make[1]: *** [stage1-bubble] Error 2 make[1]: Leaving directory `/home/roman/compiled/build_graphite_sec' make: *** [all] Error 2 Could you please advise me how to fix this? If I’m not mistaken, r216735 is the only commit related to graphite-optimize-isl.c which has been made since my latest patch. This is another incompatibility between isl 0.12 and 0.13. I suggest to first test this with isl-0.12. @Sven: Maybe Sven has an idea how to handle this best. Cheers, Tobias
Re: mt_allocator.cc assumes sizeof(size_t) == sizeof(void *)
Hi, On 11/08/2014 04:33 PM, Jonathan Wakely wrote: On 8 November 2014 15:30, Joel Sherrill wrote: This didn't compile. Ended with an error about requiring C++11 in a header file. This code is in a c++98 subdirectory so it dues make sense. I can't cut and paste it at home. Yep, that makes sense, I'd just stick with stdint.h Good. Sorry, if I missed some relatively recent development: is now GCC installing its own stdint.h on *all* the supported targets, thus we can safely assume it's unconditionally available? For many years a few "exotic" targets didn't have their own and couldn't get a stdint.h... Paolo.