====================================================================== PowerBASIC Gazette - Electronic Edition Volume 1 - Issue 3 PowerBASIC, Inc. (800) 780-7707 Sales 1978 Tamiami Trail S. #200 (941) 408-8700 Voice Venice, FL 34293-5006 (941) 408-8820 Fax Visit us on the World Wide Web at http://www.powerbasic.com Email Sales: sales@powerbasic.com PowerBASIC Inc. will be closed September 5,6,7 (Sat/Sun/Mon) in observance of our national holiday, Labor Day. This newsletter is only sent to email addresses in our subscription list. If you have received this newsletter by mistake or no longer wish to receive it, please send a simple unsubscribe request to support@powerbasic.com This newsletter is best viewed with a fixed-width font. ====================================================================== Optimize Your Code with Register Variables by Robert Zale, PowerBASIC Inc. Register variables... a powerful tool for optimization, but often overlooked or misunderstood. Many compilers use them in one form or another. Better compilers, including all 32-bit PowerBASIC products, offer automatic allocation as well as specific control by the programmer. But more about that later. So just what is a register? It's simply a small area of memory, located directly on the cpu. The Intel x86 chips offer eight 32-bit registers, while the x87 numeric coprocessor sports another eight 80-bit floating point registers. Typically, registers are used by the compiler for temporary storage and calculation. Because they're "on-chip", access is very fast... much faster than conventional memory. Even better, the code needed to access them is smaller, too! So why don't we examine the code in a Sub or Function to find a few local variables which are used the most? Then, instead of storing these popular variables in memory, just reserve a couple of the cpu registers and store them there? We'd get a big boost in speed, and smaller code size, too. There you have it: REGISTER VARIABLES. So just how much of a difference do register variables make? Let's look at a very simple example written in 32-bit PB/CC: Function PbMain() Register X&, Counter& For Counter& = 1 To 300000000 X& = Counter& + Counter& + Counter& Next End Function With Register Variables disabled on a P2/300, this runs in 7 seconds. Now, turn them on, and the identical code runs in under 4 seconds, a major improvement! That's close to double the execution speed! Will it work for floating point code, too? You bet it will! Any local, extended precision (80-bit) float variable can be declared as a Register Variable. It even helps to use them for storage of overworked numeric constants -- anything that limits memory access will help your bottom line performance. Take this simple example: Function PbMain() Register Counter& Register x##, y## x## = 1 y## = 0.00001 For Counter& = 1 To 100000000 x## = x## * y## Next End Function Watch this closely... It just gets better and better! Without the benefit of Register Variables, this code runs in about 6.7 seconds. Fairly respectable by most standards. But turn them on, and running time is slashed to just 1.6 seconds. More than four times faster! Just by telling the compiler to make full use of Register Variables. Register variables are always local to the Sub or Function where they are declared. In the current version of PowerBASIC, there may be up to two integer class register variables (word/dword/integer/long) and up to four extended precision (80-bit) floats within each Sub or Function. It's possible that future versions of the compiler will change these limits, so we place no restrictions on how many you may declare. Any "extra" register variables are simply reclassified by the compiler as locals. PowerBASIC stores the two integer class Register Variables in the CPU registers ESI and EDI, though you really don't need to worry about it unless you use inline assembler. Since these two registers aren't addressable at the byte level, PowerBASIC must disallow bytes as Register Variables. Supported integer class variables would be any of integer, long, word, and dword. As with all 32-bit programs, 32-bit data size is preferred. It's faster and the generated code is smaller, too. In the 32-bit world, avoid the use of bytes, integers, and words whenever it's reasonable. Your code will benefit! The Intel x87 numeric coprocessor offers eight 80-bit floating point registers. PowerBASIC takes four of them to store Register Variables. Since these registers are 80-bits in size, only extended precision floating point variables (such as x##) are eligible. If singles or doubles were allowed, round-off discrepancies would be introduced. Simply put, that would mean slight changes in calculation depending upon whether Register Variables were enabled: an unacceptable option. The REGISTER statement, supported in PB/CC and PB/DLL 5, allows you to choose which variables will be classified as register variables. They are local, so each Sub and Function may have its own unique set. If you do not make the choice in a particular Sub/Function, the compiler will attempt to choose for you. By default, the compiler will always assign any integer class local variables available. Extended precision float variables will be automatically allocated only in functions which contain no external function calls. The $REGISTER metastatement, also supported in PB/CC and PB/DLL 5, allows you to specify the method of auto-allocation of Register Variables. $REGISTER ALL requests automatic allocation of all possible register variables, both integer class and floating point. $REGISTER DEFAULT requests automatic allocation of integer class variables, but allocates floating point variables only in subs and functions which contain no external function calls. $REGISTER NONE disables automatic allocation of register variables. In the current version of the compilers, $REGISTER applies to the entire program. It must therefore precede any Sub or Function. Integer class register variables are almost always desirable and beneficial. It's generally best to select those which are referenced most frequently, such as For/Next Loop Counter Variables, and those used repeatedly as array indexes. Float register variables should generally be chosen with a bit more caution, since the compiler must generate code to save and restore them to conventional memory around each call to a Sub or Function. In some rather rare cases, it is possible that float register variables could actually reduce execution speed. However, they are extremely valuable with intensive floating point calculations in functions which have few references to other Subs or Functions. Due to the structure of the numeric coprocessor, and the instruction set available, the first float register variable declared in your program has far more optimization possibilities than the others. Use care in choosing the variable which is used most within floating point expressions (that is, on the right side of the '=' assignment operator), in order to gain the greatest advantage in execution speed. Also, remember it is typically valuable to assign floating point constants to register variables when they are used in repetitive or intensive calculations. So what about Register Variables and inline assembler? Generally speaking, it's pretty straightforward. In most cases, you'll only be accessing integer class variables, and you can do that by just using the variable name. For example: Register xyz& asm mov eax, xyz& asm mov eax, esi In the above example, both "mov" instructions are interpreted in exactly the same way, as PowerBASIC is smart enough to understand that the Register Variable xyz& is stored in the cpu register esi. It's much to your advantage to use intuitive variable names rather than hardware registers, for obvious reasons, so be sure you do that whenever possible. That rule always applies when you are dealing with integer class Register Variables. That is, integer, long, word, and dword Register Variables. You probably won't have nearly as much need to access floating point Register Variables from inline assembler, and that's good! If you try it, the rewards can be great, but there are hazards. You must use a good deal more care with assembler floating point code in functions with Register Variables. Floating point register variables may occupy up to four of the coprocessor registers, so you must limit your use of x87 registers to the remaining four. Further, float register variables should not be referenced by name in assembler code, as the compiler can't always track the register locations with absolute certainty. Here's why... Registers on the x87 are oriented as a stack. The first value loaded is saved in register st(0). The second value loaded goes to st(0) as well, but pushes the first to st(1). And so on, for up to eight float registers. When you declare float Register Variables, the first is stored in st(0), the second in st(1), then st(2) and st(3). Each time more values are loaded or stored, the Register Variables can shift up to four register positions in either direction! This isn't a problem with compiled PowerBASIC code, but it can be a logical nightmare with inline assembler. So the PowerBASIC rule is simple: Never, ever reference a float register variable by name from inline assembler. Just don't do it! (smile) Reference floats only by the register: st(0) through st(7). That's the safe thing to do. One final restriction: Since Register Variables have no memory location, they cannot be used with the VARPTR() function. Register Variables are supported in both 32-bit PowerBASIC compilers. PB/CC, the PowerBASIC Console Compiler, creates text mode applications for Win95/98/NT. It is ideally suited for those situations where a graphical user-interface is not needed nor desirable, such as Internet Web Server and CGI applications, or for a straightforward port of DOS Basic code to 32-bit Windows. PB/DLL, the PowerBASIC DLL Compiler, creates DLLs and executables for Win95/98/NT. Its industry-standard DLLs may be accessed from any Windows language to enhance capabilities and total performance. Teamed with PB/Forms, the Visual Designer/Code Generator, you can build state-of-the-art visual applications with ease. Both compilers offer multi-threaded capabilities, inline assembler, pointers, unsigned integers, conditional compilation, and much more. For more information, visit the PowerBASIC web site at www.powerbasic.com. ====================================================================== Order online at https://www.powerbasic.com/shop/ ====================================================================== PowerTree BTree Manager for DOS and Windows If you like "smaller and faster" then PowerTree is just what you need! PowerTree offers a concise, proprietary implementation of the highly efficient B+Tree algorithm for indexed data management. Create one index or many. Use one data file, or several, always in the format of your choice. There are no arbitrary limitations. Retrieve data sequentially, by exact match, or approximation. A single user, or hundreds, all with safety and reliability. PowerTree is FAST! Index and search thousands of records in seconds. PowerTree is SMALL! But don't let that fool you... The amazing module size just means that you won't need a stack of CD's to distribute your application. The days of fat database BloatWare are over! PowerTree creates compatible indexes for DOS, Win 16, and Win 32, though the DOS and Windows versions are sold separately. With no limitation on file format, any type of database can be indexed. With no limitation on keys, any number can be utilized, simple or compound. And with easy locking capability, multi-user and multi-threaded applications are a breeze. Best of all, PowerTree is easy to implement. There are only fourteen functions to learn, not hundreds, like the others. Create or open an index, add new entries, delete or search for existing entries. It's as simple as that! And in Windows, the DLL interface is industry standard, for immediate, efficient use with any programming language. PowerTree is for you! Order online at https://www.powerbasic.com/shop/ See more at http://www.powerbasic.com/products/powertree/ ====================================================================== Is your PowerBASIC Gazette Electronic Edition subscription coming to you at home or work? If you don't want to miss a single issue, why not subscribe from both email addresses? Send your subscription request to email@powerbasic.com and please include your name and all email addresses you'd like to add as well as your Zip or Postal Code. If you know someone else who would enjoy this newsletter please forward a copy to them so they can subscribe. You may unsubscribe at any time by sending your request to support@powerbasic.com ====================================================================== All contents Copyright (c) 1998 PowerBASIC, Inc. All Rights Reserved. PowerBASIC is a registered trademark of PowerBASIC, Inc. PB/CC and PB/DLL are trademarks of PowerBASIC, Inc. Microsoft is a registered trademark of Microsoft Corporation. Visual Basic and Windows are trademarks of Microsoft Corporation. All other brand names are trademarks or registered trademarks of their respective owners. ======================================================================