Przemyslaw Czerpak (druzus/at/priv.onet.pl) Harbour compile time optimizations. 1. Function call optimization. Just like Clipper Harbour compiler can optimize few function calls if parameters are well known constant values. Here is the list of functions optimized at compile time: - Clipper compatible: At( , ) // Clipper wrongly calculates // At( "", ) as 1 Asc( [ , ... ] ) Chr( ) Len( | | ) // is Harbour extension Upper( ) // cannot contain characters different then [0-9A-Za-z ] - Harbour extension: Int( ) Min( , ) // is N, D or L value Max( , ) // is N, D or L value Empty( | | | | | | | NIL ) CToD( "" [ , ... ] ) DToS( ] ) SToD( [ ] ) hb_SToD( [ ] ) hb_SToT( [ ] ) hb_bitNot( [, ... ] ) hb_bitAnd( , [, ] ) hb_bitOr( , [, ] ) hb_bitXor( , [, ] ) hb_bitTest( , [, ... ] ) hb_bitSet( , [, ... ] ) hb_bitReset( , [, ... ] ) hb_bitShift( , [, ... ] ) - Harbour special functions: HB_I18N_GETTEXT_NOOP( [ , ] ) HB_I18N_NGETTEXT_NOOP( , | [ , ] ) HB_I18N_GETTEXT_NOOP_*( [ , ] ) HB_I18N_NGETTEXT_NOOP_*( , | [ , ] ) hb_mutexCreate() 2. Expression optimization: Just like Clipper Harbour compiler can optimize some expressions if arguments are well known and can be calculated at compile time: - Clipper compatible: + => + => + => + => // In Clipper neither nor // can contain '&' character. Harbour checks // if concatenation can change existing valid // macro name or ignore '&' when -kM compiler // switch which disables macro substitution // is used - => - => - => - => // In Clipper neither nor // can contain '&' character. Harbour checks // if concatenation can change existing valid // macro name or ignore '&' when -kM compiler // switch which disables macro substitution // is used * => / => // Clipper optimizes only integers % => $ => // Clipper wrongly calculates // "" $ as .T. // In Clipper neither nor // can contain '&' character. Harbour checks // if after '&' is potentially valid macro // name or ignore '&' when -kM compiler switch // which disables macro substitution is used == => == => == => == => // In Clipper neither nor // can contain '&' character. Harbour checks // if after '&' is potentially valid macro // name or ignore '&' when -kM compiler switch // which disables macro substitution is used NIL == => == NIL => = => = => = => NIL = => = NIL => "" = "" => .T. != => != => != => NIL != => != NIL => "" != "" => .F. >= => >= => >= => <= => <= => <= => > => > => > => < => < => < => .NOT. .T. => .F. .NOT. .F. => .T. .AND. => .OR. => iif( .T., , ) => iif( .F., , ) => - optimizations which can be disabled by -z compiler switch .T. .AND. => .AND. .T. => .F. .OR. => .OR. .F. => .F. .AND. => .F. .AND. .F. => .F. .T. .OR. => .T. .OR. .T. => .T. - Harbour extension: ^ => [ ] => ( ) => // it allows to optimize // expressions like: 1+(2) - Harbour syntax extensions not supported by Clipper, enabled by -ko compiler switch: iif( , , ) = => ; IF ; = ; ELSE ; = ; ENDIF i.e.: iif( dData == NIL, dDate, aVal[ 1 ] ) := date() iif( empty( x ), aVal[ 2 ], nTmp ) += 10 ? iif( f1(), nVal1, nVal2 )++ ? --iif( f2(), aVal[ 1 ], hVal[ "abc" ] ) - Harbour extensions which may disable RT errors in wrong expressions or can change used operators using basic math rules. Enabled by -ko compiler switch: .NOT. .NOT. => - - => + 0 => 0 + => + "" => "" + => ( "" )-> => -> == .T. => .T. == => == .F. => ! .F. == => ! = .T. => .T. = => = .F. => ! .F. = => ! != .T. => ! .T. != => ! != .F. => .F. != => In cases when result is meaningless Harbour compiler can skip code for operation, i.e. for such line of .prg code: ( ) where result of operation is ignored Harbour reduces the code to: ( , ) In Clipper in some places optimization is not enabled, f.e. Clipper does not optimize in expressions like: : msg( ... ) Unlike Clipper Harbour tries to optimize all expressions. If some code needs strict Clipper behavior then it can be forced by using -kc Harbour compiler switch. It disables Harbour extensions and enables replicating some Clipper bugs like optimizing "" $ to .T. at compile time (at runtime and in macro-compiler it's always .F. in Clipper and Harbour). Expressions fully optimized to constant values at compile time can be used to initialize static variables, f.e.: static s_var := ( 1 + 2 / 3 ) Clipper does not optimize expression used in LOCAL, PRIVATE and PUBLIC variables declarations but it optimizes expressions for STATIC declarations. This code illustrates it: proc main() memvar v, p local l := "" $ "" static s := "" $ "" private v := "" $ "" public p := "" $ "" ? l, s, v, p, "" $ "" return This behavior is not replicated in Harbour even if -kc switch is used and Harbour optimizes expressions in all declarations. 3. Macro expansion: Harbour supports macro expansion for expressions with declared symbols. This functionality can be enabled by -kd compiler switch: -kd => accept macros with declared symbols It only allows to write code like: cbVar := {|| &cLocal + cPrivate } or: cbVar := {|| &cLocalPref.func&cPriv1( cPriv2 ) } or: ? &cLocalPref.func&cPriv1( cPriv2, &cStatic ) etc. If possible then for macro-codeblocks Harbour compiler tries to generate early eval code in which macros are expanded when codeblock is created. Otherwise macros are expanded each time codeblock is evaluated. This feature can be useful also in porting some other xBase compatible code to Harbour because some compilers just like xHarbour accepted in some limited way officially unsupported syntax with macros using declared symbols. 4. PCODE optimization: Harbour has additional optimization phase which operates on generated PCODE. It can also reduce expressions, joins jumps, removes death or meaningless code which can appear after all other optimizations and were not optimized by expression optimizer. It can also optimize read-only local variables keeping the QSelf() value. QSelf() is not real function call but very fast single PCODE often used in OOP code. Harbour can replace local variables keeping it by direct QSelf() usage.