📄 projects
字号:
0. Improved efficiency.* Parse and output array initializers an element at a time, freeingstorage after each, instead of parsing the whole initializer first andthen outputting. This would reduce memory usage for largeinitializers.* See if the techniques describe in Oct 1991 SIGPLAN Notices(Frazer and Hanson) are applicable to GCC.1. Better optimization.* Constants in unused inline functionsIt would be nice to delay output of string constants so that stringconstants mentioned in unused inline functions are never generated.Perhaps this would also take care of string constants in dead code.The difficulty is in finding a clean way for the RTL which refersto the constant (currently, only by an assembler symbol name)to point to the constant and cause it to be output.* More cseThe techniques for doing full global cse are described in the reddragon book, or (a different version) in Frederick Chow's thesis fromStanford. It is likely to be slow and use a lot of memory, but itmight be worth offering as an additional option.It is probably possible to extend cse to a few very frequent caseswithout so much expense.For example, it is not very hard to handle cse through if-thenstatements with no else clauses. Here's how to do it. On reaching alabel, notice that the label's use-count is 1 and that the lastpreceding jump jumps conditionally to this label. Now you know itis a simple if-then statement. Remove from the hash tableall the expressions that were entered since that jump insnand you can continue with cse.It is probably not hard to handle cse from the end of a looparound to the beginning, and a few loops would be greatly spedup by this.* Optimize a sequence of if statements whose conditions are exclusive.It is possible to optimize if (x == 1) ...; if (x == 2) ...; if (x == 3) ...;into if (x == 1) ...; else if (x == 2) ...; else if (x == 3) ...;provided that x is not altered by the contents of the if statements.It's not certain whether this is worth doing. Perhaps programmersnearly always write the else's themselves, leaving few opportunitiesto improve anything.* Un-cse.Perhaps we should have an un-cse step right after cse, which tries toreplace a reg with its value if the value can be substituted for thereg everywhere, if that looks like an improvement. Which is if thereg is used only a few times. Use rtx_cost to determine if thechange is really an improvement.* Clean up how cse works.The scheme is that each value has just one hash entry. Thefirst_same_value and next_same_value chains are no longer needed.For arithmetic, each hash table elt has the following slots:* Operation. This is an rtx code.* Mode.* Operands 0, 1 and 2. These point to other hash table elements.So, if we want to enter (PLUS:SI (REG:SI 30) (CONST_INT 104)), wefirst enter (CONST_INT 104) and find the entry that (REG:SI 30) nowpoints to. Then we put these elts into operands 0 and 1 of a new elt.We put PLUS and SI into the new elt.Registers and mem refs would never be entered into the table as such.However, the values they contain would be entered. There would be atable indexed by regno which points at the hash entry for the value inthat reg.The hash entry index now plays the role of a qty number.We still need qty_first_reg, reg_next_eqv, etc. to record which regsshare a particular qty.When a reg is used whose contents are unknown, we need to create ahash table entry whose contents say "unknown", as a place holder forwhatever the reg contains. If that reg is added to something, thenthe hash entry for the sum will refer to the "unknown" entry. UseUNKNOWN for the rtx code in this entry. This replaces make_new_qty.For a constant, a unique hash entry would be made based on thevalue of the constant.What about MEM? Each time a memory address is referenced, we need aqty (a hash table elt) to represent what is in it. (Just as for aregister.) If this isn't known, create one, just as for a reg whosecontents are unknown.We need a way to find all mem refs that still contain a certain value.Do this with a chain of hash elts (for memory addresses) that point tolocations that hold the value. The hash elt for the value itself shouldpoint to the start of the chain. It would be good for the hash eltfor an address to point to the hash elt for the contents of that address(but this ptr can be null if the contents have never been entered).With this data structure, nothing need ever be invalidated exceptthe lists of which regs or mems hold a particular value. It is easyto see if there is a reg or mem that is equiv to a particular value.If the value is constant, it is always explicitly constant.* Support more general tail-recursion among different functions.This might be possible under certain circumstances, such as whenthe argument lists of the functions have the same lengths.Perhaps it could be done with a special declaration.You would need to verify in the calling function that it does notuse the addresses of any local variables and does not use setjmp.* Put short statics vars at low addresses and use short addressing mode?Useful on the 68000/68020 and perhaps on the 32000 series,provided one has a linker that works with the feature.This is said to make a 15% speedup on the 68000.* Keep global variables in registers.Here is a scheme for doing this. A global variable, or a local variablewhose address is taken, can be kept in a register for an entire functionif it does not use non-constant memory addresses and (for globals only)does not call other functions. If the entire function does not meetthis criterion, a loop may.The VAR_DECL for such a variable would have to have two RTL expressions:the true home in memory, and the pseudo-register used temporarily. It is necessary to emit insns to copy the memory location into thepseudo-register at the beginning of the function or loop, and perhapsback out at the end. These insns should have REG_EQUIV notes so that,if the pseudo-register does not get a hard register, it is spilled intothe memory location which exists in any case.The easiest way to set up these insns is to modify the routineput_var_into_stack so that it does not apply to the entire function(sparing any loops which contain nothing dangerous) and to call it atthe end of the function regardless of where in the function theaddress of a local variable is taken. It would be calledunconditionally at the end of the function for all relevant globalvariables.For debugger output, the thing to do is to invent a new binding levelaround the appropriate loop and define the variable name as a registervariable with that scope.* Live-range splitting.Currently a variable is allocated a hard register either for the fullextent of its use or not at all. Sometimes it would be good toallocate a variable a hard register for just part of a function; forexample, through a particular loop where the variable is mostly used,or outside of a particular loop where the variable is not used. (Thelatter is nice because it might let the variable be in a register mostof the time even though the loop needs all the registers.)It might not be very hard to do this in global.c when a variablefails to get a hard register for its entire life span.The first step is to find a loop in which the variable is live, butwhich is not the whole life span or nearly so. It's probably best touse a loop in which the variable is heavily used.Then create a new pseudo-register to represent the variable in that loop.Substitute this for the old pseudo-register there, and insert move insnsto copy between the two at the loop entry and all exits. (When severalsuch moves are inserted at the same place, some new feature should beadded to say that none of those registers conflict merely because ofoverlap between the new moves. And the reload pass should reorder themso that a store precedes a load, for any given hard register.)After doing this for all the reasonable candidates, run global-allocover again. With luck, one of the two pseudo-registers will be fitsomewhere. It may even have a much higher priority due to its reducedlife span.There will be no room in general for the new pseudo-registers inbasic_block_live_at_start, so there will need to be a second suchmatrix exclusively for the new ones. Various other vectors indexed byregister number will have to be made bigger, or there will have to besecondary extender vectors just for global-alloc.A simple new feature could arrange that both pseudo-registers get thesame stack slot if they both fail to get hard registers.Other compilers split live ranges when they are not connected, ortry to split off pieces `at the edge'. I think splitting around loopswill provide more speedup.Creating a fake binding block and a new like-named variable withshorter life span and different address might succeed in describingthis technique for the debugger.* Detect dead stores into memory?A store into memory is dead if it is followed by another store intothe same location; and, in between, there is no reference to anythingthat might be that location (including no reference to a variableaddress).* Loop optimization.Strength reduction and iteration variable elimination could besmarter. They should know how to decide which iteration variables arenot worth making explicit because they can be computed as part of an
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -