Re: Dominance information problem
Hi Gary, I'm not 100% sure this will fix the problem, but in the past I have had to call the following function: /* If dominator info is not available, we need to calculate it. */ if (!dom_info_available_p (CDI_DOMINATORS)) calculate_dominance_info (CDI_DOMINATORS); Basically dominance information was not available for cfun. Also, you might also need to call: if (dom_info_available_p (CDI_DOMINATORS)) free_dominance_info (CDI_DOMINATORS); Just before your pass is done. These were some calls I needed to make in a different pass when I was working with dominators. On 12/09/2020 09:26, Gary Oblock wrote: I'm trying to do performance qualification for my structure reorganization optimization. I'm doing pretty straightforward stuff and I haven't at this point in time (qualifying the optimization,) modified the program. So I'm a little surprised this is failing. Here is the code that's failing on the first iteration of the for loops: struct cgraph_node *node; FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) { struct function *func = DECL_STRUCT_FUNCTION ( node->decl); push_cfun ( func); class loop *loop; FOR_EACH_LOOP_FN ( func, loop, LI_ONLY_INNERMOST ) { size_t num_bbs = loop->num_nodes; basic_block *bbs = get_loop_body ( loop); // FAILS HERE!!! : stuff never reached How it's failing (in code from dominance.c) I'm guessing tells me the dominance information is messed up (unlikely) or needs to be recomputed. If I'm not wrong, how do I go about doing the later /* Return TRUE in case BB1 is dominated by BB2. */ bool dominated_by_p (enum cdi_direction dir, const_basic_block bb1, const_basic_block bb2) { unsigned int dir_index = dom_convert_dir_to_idx (dir); struct et_node *n1 = bb1->dom[dir_index], *n2 = bb2->dom[dir_index]; gcc_checking_assert (dom_computed[dir_index]); // <=== BOOM! if (dom_computed[dir_index] == DOM_OK) return (n1->dfs_num_in >= n2->dfs_num_in && n1->dfs_num_out <= n2->dfs_num_out); return et_below (n1, n2); } Thanks, Gary Oblock CONFIDENTIALITY NOTICE: This e-mail message, including any attachments, is for the sole use of the intended recipient(s) and contains information that is confidential and proprietary to Ampere Computing or its subsidiaries. It is to be used solely for the purpose of furthering the parties' business relationship. Any unauthorized review, copying, or distribution of this email (or any attachments thereto) is strictly prohibited. If you are not the intended recipient, please contact the sender immediately and permanently delete the original and any copies of this email and any attachments thereto.
Re: A problem with one instruction multiple latencies and pipelines
On 14/09/2020 03:53, Qian, Jianhua wrote: >> -Original Message- >> From: Richard Earnshaw >> Sent: Friday, September 11, 2020 9:30 PM >> To: Qian, Jianhua/钱 建华 ; gcc@gcc.gnu.org >> Subject: Re: A problem with one instruction multiple latencies and pipelines >> >> On 07/09/2020 07:08, Qian, Jianhua wrote: >>> Hi >>> >>> I'm adding a new machine model. I have a problem when writing the >> "define_insn_reservation" for instruction scheduling. >>> How to write the "define_insn_reservation" for one instruction that there >>> are >> different latencies and pipelines according to parameter. >>> >>> For example, the ADD (shifted register) instruction in a64fx >>> >>> InstructionOption Latency >> Pipeline >>> ADD (shifted register) = 0 1 EX* >> | EAG* >>>= [1-4] && =LSL 1+1 >> (EXA + EXA) | (EXB + EXB) >>> 2+1 (EXA >> + EXA) | (EXB + EXB) >>> >> >> A shift by immediate zero isn't a shift, so should never use this RTL >> pattern. >> We can ignore that case. >> >>> In aarch64.md ADD (shifted register) instruction is defined as following. >>> (define_insn "*add__" >>> [(set (match_operand:GPI 0 "register_operand" "=r") >>> (plus:GPI (ASHIFT:GPI (match_operand:GPI 1 "register_operand" >> "r") >>> (match_operand:QI 2 >> "aarch64_shift_imm_" "n")) >>> (match_operand:GPI 3 "register_operand" "r")))] >>> "" >>> "add\\t%0, %3, %1, %2" >>> [(set_attr "type" "alu_shift_imm")] >>> ) >> >> You might consider using a define_bypass to adjust the cost - the matcher >> rule >> takes a producer and consumer RTL - you don't care about the consumer, but >> you can use the bypass to reduce the cost if the producer uses an immediate >> in >> the 'low latency' range. This would avoid having to make a load of >> whole-sale >> changes to the main parts of the machine description. > > Thanks for your comment. > But I think the define_bypass can only change the latency for special > instruction. > Pipeline also could be changed by define_bypass? > Possibly, but if this is part of the out-of-order units of the pipe, I really don't think it will matter. In fact, I'm not even convinced that trying to model the out-of-order stages is worthwhile - let the CPU handle that: any long-latency instruction, such as a memory access that misses the L1 cache will completely mess up the compiler's understanding of the pipeline state anyway. What I think is more important is to get a good model for the in-order bits at the front of the pipe accurately modelled so that you can maximize the throughput of those stages. Try to get a mix of instructions so that a single issue unit in the core doesn't get clogged up and block further decode. R. > Regards > Qian > >>> >>> It could not be distinguished by the type "alu_shift_imm" when writing >> "define_insn_reservation" for ADD (shifted register). >>> What should I do? >>> >>> Regards >>> Qian >>> >>> >>> >> >> R. >> > > >
Re: A problem with one instruction multiple latencies and pipelines
"Qian, Jianhua" writes: > Hi Richard and Segher > > I don't know if I exactly understood your discussion. > If I misunderstood, please let me know. > > I am trying to test these two cases. > Case 1. keep the TYPE attribute unchanged, add new attributes > It works well as below. > (define_attr "shift_imm_value" > "shift_imm_none,shift_imm_0,shift_imm_1to4,shift_imm_ge5" (const_string > "shift_imm_none")) I'm not sure the shift_imm_0 case is useful here FWIW. alu_shift_imm should only be used with nonzero shift amounts. Also, the associated C++ enums are automatically prefixed with the name of the attribute, so I think the values should just be 1to4, ge5, etc., with no prefix. > (define_insn "*add__" > [(set (match_operand:GPI 0 "register_operand" "=r") > (plus:GPI (ASHIFT:GPI (match_operand:GPI 1 "register_operand" "r") > (match_operand:QI 2 > "aarch64_shift_imm_" "n")) > (match_operand:GPI 3 "register_operand" "r")))] > "" > "add\\t%0, %3, %1, %2" > [(set_attr "type" "alu_shift_imm") >(set (attr "shift_imm_value") > (cond [(eq (symbol_ref "XINT(operands[2],0)") (const_int 0)) > (const_string "shift_imm_0") >(and (ge (symbol_ref "XINT(operands[2],0)") (const_int 1)) > (le (symbol_ref "XINT(operands[2],0)") (const_int 4))) (const_string > "shift_imm_1to4")] >(const_string "shift_imm_ge5")))] > ) I'll come back to this below. > > (define_insn_reservation "a64fx_alu_shift1to4" 2 > (and (eq_attr "tune" "a64fx") >(eq_attr "type" "alu_shift_imm") >(eq_attr "shift_imm_value" "shift_imm_1to4")) > "(a64fx_exa,a64fx_exa)|(a64fx_exb,a64fx_exb)") > > > Case2. expand the TYPE attribute > I replaced the alu_shift_imm to alu_shift_imm, alu_shift_imm1to4, and I > got the error message " bad number of entries in SET_ATTR_ALTERNATIVE, was 2 > expected 1" > (define_attr "type" > ... > alu_shift_imm,\ > alu_shift_imm1to4,\ > ... > > (define_insn "*add__" > [(set (match_operand:GPI 0 "register_operand" "=r") > (plus:GPI (ASHIFT:GPI (match_operand:GPI 1 "register_operand" "r") > (match_operand:QI 2 > "aarch64_shift_imm_" "n")) > (match_operand:GPI 3 "register_operand" "r")))] > "" > "add\\t%0, %3, %1, %2" > [(set_attr "type" "alu_shift_imm,alu_shift_imm1to4")] > ) > > It means that one "type" value should be matched by one operand > constraint pattern. So this will raise two problems. > 1. One instruction should be classified to multiple patterns > - define multiple operand constraints, such as "(match_operand:QI 2 > "aarch64_shift_imm_" "0, 1to4, ...")" > - or, use "cond" at set_attr just like Case1. > 2. Whatever you do with the first problem, the type attribute cannot be > set with "alu_shift_imm" > and "alu_shift_imm1to4" at the same time by one operand constraint > pattern. Right. Something needs to tell the compiler how to distinguish between the two cases. > - If we cannot resolve it, the existing CPUs' descriptions need > to be changed. This is not what I expected. > - If we want to add new attribute to resolve this problem, why > not use the Case1 directly? It's a trade-off. At the moment the rule for arm and aarch64 is simple: the "type" attribute specifies the complete scheduling type. If we instead change policy and divide the information among several attributes, those attributes will have increasingly complex relationships with one another. It will become easier to specify a meaningless combination by mistake, or to forget to specify one of the relevant attributes. I agree it's not so bad with just one extra attribute. The question is more: if we change the policy, what would things look like if there were more attributes of a similar nature? On the other side, lumping everything into one attributes gives a long list of values. I think the difference of opinion is that Segher finds this argument more compelling while I find the other argument more compelling ;-) That said, there are really two issues here: (1) how should the define_insn describe the instruction? (2) how should scheduling descriptions test for it? The same answer for (1) can support multiple answers for (2). For (1), I think we should do what I mentioned in my first reply and add something like (different name from last time): ;; config/arm/types.md (define_attr "autodetect_type" "none,alu_shift_op2") This attribute would in principle be a home for any case in which the scheduling type needs to be derived from other information (in this case using the contents of operand 2 to infer the alu_shift kind). So going back to what I said above: we would be changing policy so that define_insns can use one of *two*
Re: "gcc -E" does not honor #pragma
On 9/13/20 2:18 PM, Chelsea Meyers via Gcc wrote: Hi, I'm new to contributing to GCC, so I looked for issues in Bugzilla with the keyword "easyhack" that looked comprehensible to me, and found bug 53920: "'gcc -E' does not honor #pragma GCC diagnostic ignored '-Wunused-macro'". I verified using a fresh build of gcc from the master branch that when "gcc -E -Wunused-macros" is used to invoke the preprocessor on the following two lines, a warning is given for the unused FOO macro despite the #pragma directive: #pragma GCC diagnostic ignored "-Wunused-macros" #define FOO My impression is that the preprocessor is ignoring the content of pragma diagnostics when invoked with -E, and that the proposed change is to add support for handling pragma diagnostics for this use case. The Bugzilla entry for this issue hasn't been commented on since 2013, so I want to make sure this is actually a good thing to work on. Might there be a reason why support for handling pragma diagnostics is missing from c-ppoutput.c? I'm not aware of a reason. IIUC in -E pragmas go through to the cpp output, as they're needed by the compiler proper. However, this is a case of a preprocessor warning, which I guess got forgotten about. I suppose diagnostic options should both be propagated into the output /and/ acted upon? Don't forget that '-E -fdirectives-only' will want to defer macro checking until proper compilation, and in general would be difficult to get right, considering #define bob 1 #if bob #else #endif where 'bob' is only used during the preprocessing. nathan -- Nathan Sidwell
Import license issue
Hi All, I need to update include/hsa.h to access some newer APIs. The existing file was created by copying from the user manual, thus side-stepping licensing issues, but the updated user manual omits some important details from the APIs I need (mostly the contents of structs and value of enums). Of course, I can go see those details in the source, but that's not the same thing. So, what I would like to do is import the header files I need into the GCC sources; there's precedent for importing (unmodified) copyright files for libffi etc., AFAICT, but of course the license needs to be acceptable. The relevant files are here: https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/master/src/inc/hsa.h https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/master/src/inc/hsa_ext_amd.h https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/master/src/inc/hsa_ext_image.h When I previously enquired about this on IRC I was advised that the Illinois license would be unacceptable because it contains an attribution clause that would require all binary distributors to credit AMD in their documentation, which seems like a reasonable position. I've requested that AMD provide a copy of these specific files with a more acceptable license, and I may yet be successful, but it's not that simple. The problem is that GCC already has this exact same license in libsanitizer/LICENSE.TXT so, again reasonably, AMD want to know why that licence is acceptable and their license is not. Looking at the files myself, there appears to be some kind of dual license thing going on, and the word "Illinois" doesn't actually appear in any libsanitizer source file (many of which contain an Apache license header). Does this mean that the Illinois license is not actually active here? Or is it that it is active and binary distributors really should be obeying this attribution clause already? Can anybody help me untangle this, please? Are the files acceptable, and if not, how is this different from the other cases? Thanks very much Andrew
Re: Dominance information problem
Erick, I assume that this needs to be done on all the functions since you mention "cfun". Gary From: Erick Ochoa Sent: Monday, September 14, 2020 12:10 AM To: Gary Oblock ; gcc@gcc.gnu.org Subject: Re: Dominance information problem [EXTERNAL EMAIL NOTICE: This email originated from an external sender. Please be mindful of safe email handling and proprietary information protection practices.] Hi Gary, I'm not 100% sure this will fix the problem, but in the past I have had to call the following function: /* If dominator info is not available, we need to calculate it. */ if (!dom_info_available_p (CDI_DOMINATORS)) calculate_dominance_info (CDI_DOMINATORS); Basically dominance information was not available for cfun. Also, you might also need to call: if (dom_info_available_p (CDI_DOMINATORS)) free_dominance_info (CDI_DOMINATORS); Just before your pass is done. These were some calls I needed to make in a different pass when I was working with dominators. On 12/09/2020 09:26, Gary Oblock wrote: > I'm trying to do performance qualification for my structure > reorganization optimization. > > I'm doing pretty straightforward stuff and I haven't at this point in > time (qualifying the optimization,) modified the program. So I'm a > little surprised this is failing. Here is the code that's failing on > the first iteration of the for loops: > >struct cgraph_node *node; >FOR_EACH_FUNCTION_WITH_GIMPLE_BODY ( node) { > struct function *func = DECL_STRUCT_FUNCTION ( node->decl); > push_cfun ( func); > > class loop *loop; > FOR_EACH_LOOP_FN ( func, loop, LI_ONLY_INNERMOST ) >{ > size_t num_bbs = loop->num_nodes; > basic_block *bbs = get_loop_body ( loop); // FAILS HERE!!! > : > stuff never reached > > How it's failing (in code from dominance.c) I'm guessing tells me the > dominance information is messed up (unlikely) or needs to be > recomputed. If I'm not wrong, how do I go about doing the later > > /* Return TRUE in case BB1 is dominated by BB2. */ > bool > dominated_by_p (enum cdi_direction dir, const_basic_block bb1, > const_basic_block bb2) > { >unsigned int dir_index = dom_convert_dir_to_idx (dir); >struct et_node *n1 = bb1->dom[dir_index], *n2 = bb2->dom[dir_index]; > >gcc_checking_assert (dom_computed[dir_index]); // <=== BOOM! > >if (dom_computed[dir_index] == DOM_OK) > return (n1->dfs_num_in >= n2->dfs_num_in > && n1->dfs_num_out <= n2->dfs_num_out); > >return et_below (n1, n2); > } > > > Thanks, > > Gary Oblock > > > > > > > CONFIDENTIALITY NOTICE: This e-mail message, including any attachments, is > for the sole use of the intended recipient(s) and contains information that > is confidential and proprietary to Ampere Computing or its subsidiaries. It > is to be used solely for the purpose of furthering the parties' business > relationship. Any unauthorized review, copying, or distribution of this email > (or any attachments thereto) is strictly prohibited. If you are not the > intended recipient, please contact the sender immediately and permanently > delete the original and any copies of this email and any attachments thereto. >
Re: A problem with one instruction multiple latencies and pipelines
Hi! On Mon, Sep 14, 2020 at 10:55:35AM +0100, Richard Sandiford wrote: > "Qian, Jianhua" writes: > > - If we cannot resolve it, the existing CPUs' descriptions need > > to be changed. This is not what I expected. > > - If we want to add new attribute to resolve this problem, why > > not use the Case1 directly? > > It's a trade-off. At the moment the rule for arm and aarch64 is simple: > the "type" attribute specifies the complete scheduling type. If we > instead change policy and divide the information among several attributes, > those attributes will have increasingly complex relationships with one > another. It will become easier to specify a meaningless combination > by mistake, or to forget to specify one of the relevant attributes. I found exactly the opposite, when I did this to rs6000: this is much *less* error-prone. > I agree it's not so bad with just one extra attribute. The question > is more: if we change the policy, what would things look like if there > were more attributes of a similar nature? You often can do new attributes that apply to quite a few different instructions. Like, as an extreme example, we have ;; What data size does this instruction work on? ;; This is used for insert, mul and others as necessary. (define_attr "size" "8,16,32,64,128" (const_string "32")) But there also is ;; Is this instruction record form ("dot", signed compare to 0, writing CR0)? ;; This is used for add, logical, shift, exts, mul. (define_attr "dot" "no,yes" (const_string "no")) and a few more. But just that: a few. It isn't good to have very many extra attributes, in the same way that very many insn types makes things harder than needed. > On the other side, lumping everything into one attributes gives a > long list of values. I think the difference of opinion is that Segher > finds this argument more compelling while I find the other argument > more compelling ;-) It's a trade-off, we agree on that :-) And I'd be conservative here, we agree on that as well. > Although this looks/sounds complicated, the advantage is that everything > remains up-to-date. If we instead added a second attribute and only > defined it for instructions like *add__, other instructions > (including config/arm instructions) would still have type alu_shift_imm > but would have a shift_imm_value of "none". I would make an attribute for the mode (or data size really), and one that says the insn uses shifted data (since many arm insns have that, just like record form on PowerPC is everywhere). And you can have that one filled "by magic" usually! Segher
Re: A problem with one instruction multiple latencies and pipelines
Segher Boessenkool writes: >> Although this looks/sounds complicated, the advantage is that everything >> remains up-to-date. If we instead added a second attribute and only >> defined it for instructions like *add__, other instructions >> (including config/arm instructions) would still have type alu_shift_imm >> but would have a shift_imm_value of "none". > > I would make an attribute for the mode (or data size really), and one > that says the insn uses shifted data (since many arm insns have that, > just like record form on PowerPC is everywhere). And you can have that > one filled "by magic" usually! I don't think this is really answering my point above though. What I meant is: we currently have several instructions in config/arm and config/aarch64 that have type alu_shift_imm. If we add some new on-the-side attributes A, but only update *some* of the alu_shift_imm instructions to define A (either directly or indirectly), then the other alu_shift_imm instructions will have the default values for A. This probably isn't the intended effect. Ideally, every alu_shift_imm instruction would specify correct attribute values for A (specifically, to indicate whether the shift value is in [1, 4] or not). In contrast, one advantage of replacing the existing alu_shift_imm type with two new types is that any existing reference to the old type will cause a build failure. So keeping everything in a single type attributes gives us static type checking that the information for each (former) alu_shift_imm instruction is complete. Similarly for any other type that needs to be split in the same way. I realise this won't convince you, and I'm not trying to. :-) Thanks, Richard
Re: A problem with one instruction multiple latencies and pipelines
On Mon, Sep 14, 2020 at 08:35:44PM +0100, Richard Sandiford wrote: > Segher Boessenkool writes: > >> Although this looks/sounds complicated, the advantage is that everything > >> remains up-to-date. If we instead added a second attribute and only > >> defined it for instructions like *add__, other instructions > >> (including config/arm instructions) would still have type alu_shift_imm > >> but would have a shift_imm_value of "none". > > > > I would make an attribute for the mode (or data size really), and one > > that says the insn uses shifted data (since many arm insns have that, > > just like record form on PowerPC is everywhere). And you can have that > > one filled "by magic" usually! > > I don't think this is really answering my point above though. > What I meant is: we currently have several instructions in config/arm > and config/aarch64 that have type alu_shift_imm. If we add some new > on-the-side attributes A, but only update *some* of the alu_shift_imm > instructions to define A (either directly or indirectly), then the other > alu_shift_imm instructions will have the default values for A. > This probably isn't the intended effect. Ideally, every alu_shift_imm > instruction would specify correct attribute values for A (specifically, > to indicate whether the shift value is in [1, 4] or not). > > In contrast, one advantage of replacing the existing alu_shift_imm type > with two new types is that any existing reference to the old type will > cause a build failure. So keeping everything in a single type > attributes gives us static type checking that the information for each > (former) alu_shift_imm instruction is complete. Similarly for any other > type that needs to be split in the same way. Removing the old types causes build failures as well if you forget some cases. > I realise this won't convince you, and I'm not trying to. :-) And you don't have to :-) I am telling you about a scheme that worked really well for us; I am not trying to convince you to do that in your own target, that decision is all your own. Segher
Re: PowerPC long double Mangling
On Wed, Sep 09, 2020 at 02:42:36PM +0100, Jonathan Wakely wrote: > Sorry for the slow reply to this. > > On Fri, 7 Aug 2020 at 22:14, Michael Meissner wrote: > > > > One issue with doing the transition is what mangling should be used with the > > new long double. > > > > At the moment, the current mangling is: > > long double "g" > > __float128 "u9__ieee128" > > __ibm128"g" > > > > Obviously this will have to change in the future. It is unfortunate that we > > choose "g" to mean IBM extended double many many years ago, when it should > > have > > been used for IEEE 128-bit floating point. But that is long ago, so I > > think we > > need to keep it. > > > > But assuming we want compatibility with libraries like glibc and libstdc++, > > I > > think we will have to continue to use "g" for __ibm128. > > > > With the long double change, I tend to view this as an ABI change. But if > > the > > user doesn't use long double, they should be able to link without changes. > > > > I would propose using a new mangling for IEEE 128-bit long double. I would > > prefer to get agreement on what the new mangling should be so we don't have > > an > > issue like we had in GCC 8.1 going to GCC 8.2, where we changed the > > mangling, > > and had to provide aliases for the old name. > > > > At the moment I think the mangling should be: > > long double "g" if long double is IBM > > long double "u12_ieee128_ld"if long double is IEEE > > __float128 "u9__ieee128" > > __ibm128"g" > > What's the benefit of having __float128 and IEEE long double be > distinct types? That complicates things for libraries like libstdc++. > If we want to support using "__float128" with C++ iostreams then we > need yet another set of I/O routines, even though it's identical to > one of the types we already handle. Why not just keep __float128 and > __ieee128 and "long double when long double is IEEE" as three > different aliases for the same type, so that C++ code like > _Z4funcu9__ieee128 works for all of them, instead of needing to also > define _Z4funcu12__ieee128_ld? The Boost library has methods that have both long double and __float128 in it. My main concern is not to break user code like Boost that the users may added __float128. Obviously with glibc and libstdc++ we have people who understand the issues, but who knows what other libraries people have come up with. So if we configure long double to be IEEE 128-bit, under the current code it would be an error. Consider this silly code. Yes it likely would be a template, but the issue is if the user mixes __float128 and long double, is it an error if long double has the same representation as IEEE 128-bit: class foo { public: double add (double a, double b) { return a+b; } long double add (long double a, long double b) { return a+b; } __float128 add (__float128 a, __float128 b) { return a+b; } }; foo x; __float128 bletch_f128 (__float128 a, __float128 b) { return x.add (a, b); } long double bletch_ld (long double a, long double b) { return x.add (a, b); } If we compile this with the current compiler, it compiles fine if long double uses the IBM extended double. But if we compile it with -Wno-psabi -mabi=ieeelongdouble, we get: In file included from foo-class.cpp:1: foo-class.h:5:14: error: ‘long double foo::add(long double, long double)’ cannot be overloaded with ‘long double foo::add(long double, long double)’ 5 | __float128 add (__float128 a, __float128 b) { return a+b; } | ^~~ foo-class.h:4:15: note: previous declaration ‘long double foo::add(long double, long double)’ 4 | long double add (long double a, long double b) { return a+b; } | ^~~ Because right now the compiler only has two types, whatever long double is, and whatever is not long double. You have the same issue right now with __ibm128 and the current long double, but I'm not convinced anybody outside of glibc and libstdc++ really uses it. Since people do use __float128, since the x86_64 port supports it, it is an issue. If you use the -mlong-double-128 option on the X86_64 compiler, you get an error, though in this case it is a more cryptic error message (compiler used was a 10.2 compiler): foo-class.cpp:15:1: error: Two symbols with same comdat_group are not linked by the same_comdat_group list. 15 | } | ^ _ZN3foo3addEgg/2 (__float128 foo::add(__float128, __float128)) @0x7f0068b922d0 Type: function definition analyzed Visibility: public weak comdat comdat_group:_ZN3foo3addEgg one_only previous sharing asm name: 1 References: Referring: