/* minimum alignment of unsigned int */ #define ALIGNMENT_UNSIGNED_INT 4 /* minimum alignment of long */ #define ALIGNMENT_LONG 4 /* minimum alignment of float */ #define ALIGNMENT_FLOAT 4 /* minimum alignment of double */ #define ALIGNMENT_DOUBLE 4
Use PK_FLT(addr), PK_DBL(addr) to read StgFloat and StgDouble values from the stack/heap, and ASSIGN_FLT(val,addr)/ ASSIGN_DBL(val,addr) to assign StgFloat/StgDouble values to heap/stack locations. These macros take care of alignment restrictions.
Heap/Stack locations are StgWord aligned; the alignment requirements of an StgDouble may be more than that of StgWord, but we don't pad misaligned StgDoubles (doing so would be too much hassle).
Doing a direct assignment/read of an StgDouble to/from a mis-aligned location may not work, so we use the ASSIGN_DBL(,)/PK_DBL() macro, which goes via a temporary.
Problem: if the architecture allows mis-aligned accesses, but prefers aligned accesses, these macros just add an extra level of indirection. We need to distinguish between an architecture that allows mis-aligned accesses and one that just imposes a performance penalty (this is most of them). Perhaps have PREFERRED_ALIGNMENT and REQUIRED_ALIGMENT configurations?
#ifdef solaris_HOST_OS // do something solaris specific #endifInstead, add an appropriate test to the configure.in script and use the result of that test instead.
#ifdef HAVE_BSD_H // use a BSD library #endifThe problem is that things change from one version of an OS to another - things get added, things get deleted, things get broken, some things are optional extras. Using "feature tests" instead of "system tests" makes things a lot less brittle. Things also tend to get documented better.
The ideas in this section are mostly aimed at this issue:
typedef enum { i_INTERNAL_ERROR /* Instruction 0 raises an internal error */ , i_PANIC /* irrefutable pattern match failed! */ , i_ERROR /* user level error */ ...
In particular:
#define add(x,y) ((x)+(y))instead of
#define add(x,y) x+y
#define ASSIGN_CC_ID(ccID) \ { \ ccID = CC_ID; \ CC_ID++; \ }but it's better to use the "do { ... } while (0)" trick instead:
#define ASSIGN_CC_ID(ccID) \ do { \ ccID = CC_ID; \ CC_ID++; \ } while(0)The following explanation comes from The Usenet C programming FAQ
10.4: What's the best way to write a multi-statement macro? A: The usual goal is to write a macro that can be invoked as if it were a statement consisting of a single function call. This means that the "caller" will be supplying the final semicolon, so the macro body should not. The macro body cannot therefore be a simple brace-enclosed compound statement, because syntax errors would result if it were invoked (apparently as a single statement, but with a resultant extra semicolon) as the if branch of an if/else statement with an explicit else clause. The traditional solution, therefore, is to use #define MACRO(arg1, arg2) do { \ /* declarations */ \ stmt1; \ stmt2; \ /* ... */ \ } while(0) /* (no trailing ; ) */ When the caller appends a semicolon, this expansion becomes a single statement regardless of context. (An optimizing compiler will remove any "dead" tests or branches on the constant condition 0, although lint may complain.) If all of the statements in the intended macro are simple expressions, with no declarations or loops, another technique is to write a single, parenthesized expression using one or more comma operators. (For an example, see the first DEBUG() macro in question 10.26.) This technique also allows a value to be "returned." References: H&S Sec. 3.3.2 p. 45; CT&P Sec. 6.3 pp. 82-3.
#define doNothing() do { } while (0)
// you can use this as an l-value or an l-value #define PROF_INFO(cl) (((StgClosure*)(cl))->header.profInfo) // polymorphic case // but note that min(min(1,2),3) does 3 comparisions instead of 2!! #define min(x,y) (((x)<=(y)) ? (x) : (y))
When a function is both inline and `static', if all calls to the function are integrated into the caller, and the function's address is never used, then the function's own assembler code is never referenced. In this case, GNU CC does not actually output assembler code for the function, unless you specify the option `-fkeep-inline-functions'. Some calls cannot be integrated for various reasons (in particular, calls that precede the function's definition cannot be integrated, and neither can recursive calls within the definition). If there is a nonintegrated call, then the function is compiled to assembler code as usual. The function must also be compiled as usual if the program refers to its address, because that can't be inlined. When an inline function is not `static', then the compiler must assume that there may be calls from other source files; since a global symbol can be defined only once in any program, the function must not be defined in the other source files, so the calls therein cannot be integrated. Therefore, a non-`static' inline function is always compiled on its own in the usual fashion. If you specify both `inline' and `extern' in the function definition, then the definition is used only for inlining. In no case is the function compiled on its own, not even if you refer to its address explicitly. Such an address becomes an external reference, as if you had only declared the function, and had not defined it. This combination of `inline' and `extern' has almost the effect of a macro. The way to use it is to put a function definition in a header file with these keywords, and put another copy of the definition (lacking `inline' and `extern') in a library file. The definition in the header file will cause most calls to the function to be inlined. If any uses of the function remain, they will refer to the single copy in the library.
int* p, q;looks like it declares two pointers but, in fact, only p is a pointer. It's safer to write this:
int* p; int* q;You could also write this:
int *p, *q;but Alastair prefers to split the declarations.
Examples:
typedef enum { /* N.B. Used as indexes into arrays */ NO_HEAP_PROFILING, HEAP_BY_CC, HEAP_BY_MOD, HEAP_BY_GRP, HEAP_BY_DESCR, HEAP_BY_TYPE, HEAP_BY_TIME } ProfilingFlags;instead of
# define NO_HEAP_PROFILING 0 /* N.B. Used as indexes into arrays */ # define HEAP_BY_CC 1 # define HEAP_BY_MOD 2 # define HEAP_BY_GRP 3 # define HEAP_BY_DESCR 4 # define HEAP_BY_TYPE 5 # define HEAP_BY_TIME 6and
typedef enum { CCchar = 'C', MODchar = 'M', GRPchar = 'G', DESCRchar = 'D', TYPEchar = 'Y', TIMEchar = 'T' } ProfilingTag;instead of
# define CCchar 'C' # define MODchar 'M' # define GRPchar 'G' # define DESCRchar 'D' # define TYPEchar 'Y' # define TIMEchar 'T'ToDo: at the time of writing, we still use the former.
#define stgCast(ty,e) ((ty)(e))
On which note: Hugs related pieces of code often start with the line:
/* -*- mode: hugs-c; -*- */which helps Emacs mimic the indentation style used by Mark P Jones within Hugs. Add this to your .emacs file.
(defun hugs-c-mode () "C mode with adjusted defaults for use with Hugs (based on linux-c-mode)" (interactive) (c-mode) (setq c-basic-offset 4) (setq indent-tabs-mode nil) ; don't use tabs to indent (setq c-recognize-knr-r nil) ; no K&R here - don't pay the price ; no: (setq tab-width 4) (c-set-offset 'knr-argdecl-intro 0) (c-set-offset 'case-label 0) (c-set-offset 'statement-case-intro '++) (c-set-offset 'statement-case-open '+) )
If you must reindent or reorganise, don't do anything else in that commit and give advance warning that you're about to do it in case anyone else is changing that file.