yuazhang

Hi,

I am reading the code of loop Instrumentation example. It seems that, it only does critical edge splitting for the outer most loop, but not for the childen loops. Why is it like this

Another question is that I saw both codes " Phx::IR::VariableOperand::New " and " Phx::IR:Surpriseperand::NewVariable" to create an operand. Is there any difference

Thanks a lot!

Regards,
Ray


Re: Phoenix A question about LoopInstrumentation of Summerworkshop

Andy Ayers - MSFT

Hey, good catch. You've found a bug in the sample! The code should recurse down to the child loops. I will say that in testing this a while back it was hard for me to create cases where edge splitting was necessary. If you do extend the code to split inner loops you may run into a second problem, which is that the splitting will create new blocks that need to be added to the set of blocks in the outer loop.

As for your second question, there is no difference in the two. In the IR package there are many examples of this, that is to say method pairs of the form Phx.IR.Y.NewX & Phx.IR.XY.New where both do the same thing.






Re: Phoenix A question about LoopInstrumentation of Summerworkshop

yuazhang

Hi Andy,


Thank you for your answers! I have another question about "_printf" symbol creation. It seems that for every loop header, it creates one and insert it into modulUnit symbol table, the same as local varibale "loop counter".

I can understand that for "loop counter", each loop header should have one local varialbe. but for "_printf", why creating it for each loop header in the moduleUnit symbol table Or, I guess, all the "_printf" will point to the same one symbol in the moduleUnit symbol table

Thank you very much!

Regards,
Ray




Re: Phoenix A question about LoopInstrumentation of Summerworkshop

Andy Ayers - MSFT

Again, thanks for pointing out an issue in our sample code. I originally intended to update the code to just create one _printf, but as you noted, the code is not actually fixed, and ends up creating many such symbols (that's the signficance of the cryptic "XXX move to parent" comment -- I wanted to just do the creation once and look up the result when instrumenting each loop).

This may come as a surprise, but creation of multiple symbols for _printf doesn't impact correctness in this case (but is a bit inefficient). Earlier, when I stated that there would be only one function symbol per function, I was speaking of the expected behavior: the existing compiler will not create multiple symbols for a function, but a plugin might end up inadvertently doing so.






Re: Phoenix A question about LoopInstrumentation of Summerworkshop

yuazhang

Hi Andy,

Thank you for you explaining! So for one function, it could have multiple function symbols associated with it in the ModuleUnit Symbol table because of plugin behavior, right

I am still a little confused by "_printf".

First, why do these multiple symbols named "_printf" refer to the same printf () function when you created them in the code I didn't see the codes that indicate they are pointing to the same "printf" function.

Second, usually, in the C code, if we want to use printf() libraray function, we have to include a header file, such as "stdio.h". But here, we just simply insert a function symbol "_printf", and then can use it. How can we ensure that this function symbol is actually using the library function "printf". I didn't see this codes neither. I want to know this because I am thinking the case that if I want to add a new function into the IR and use it.

Thank you very much!

Regards,
Ray






Re: Phoenix A question about LoopInstrumentation of Summerworkshop

Andy Ayers - MSFT

Yes, it is possible to have multiple symbols for the same thing -- but I'd encourage you not to make this a habit, since as you point out it's confusing. We might consider outlawing it, but detecting it has a cost and there are other cases and other languages where duplicate names might not be wrong. (Consider even in C/C++ that a function can have many distinct local variables named 'x').

The thing to realize is that the compiler usually has no idea what actual function the external functions will resolve to -- that's the linker's job to determine. All the compiler knows is the names of these functions, and it's the role of the function symbols to remember these names. So we don't actually know for sure that when we introduce a call to _printf that it will be linked up with the printf provided by the C Runtime Library (aka CRT). And this is what makes the multiple symbols named "_printf" work out ok in the end, because they all have the same name and so to the linker they all refer to the same function.

The header file case you mention actually also does not really specify which function will actually be called -- just its name. You need to link the compiled file with the right object to complete the connection. Compilers and linkers will often play various tricks to try and make it harder for you to accidentally use a standard function name as one of your own. Look at the /NODEFAULTLIB option to the linker for an example: when you include a standard CRT header, we emit a note into the object file telling the linker that we expect to be linking in the CRT. If you don't tell the linker otherwise, the right thing happens "magically". But the ability to override standard functions is sometimes useful, so there are ways to have _printf resolve to some other function that you provide.

At any rate, if you use a plugin to introduce new calls, it is your responsibility to make sure that the right libraries or objects are provided to the linker to complete the picture.