 |
HP C++ V7.3 Release Notes for OpenVMS Industry Standard 64
(I64) for Integrity Servers
HP C++ V7.3 Release Notes for OpenVMS Industry
Standard 64 (I64) for Integrity Servers
November, 2007
This document contains information about new and changed features in
HP C++ V7.3 for OpenVMS I64 Version 8.2-1.
Revision/Update Information:
This is a new manual
Software Version:
HP C++ V7.3 for OpenVMS Industry Standard 64 for Integrity
Servers Version 8.2-1 and higher.
Hewlett-Packard Company Palo Alto, California
© Copyright 2007 Hewlett-Packard Development Company, L.P.
Confidential computer software. Valid license from HP required for
possession, use or copying. Consistent with FAR 12.211 and 12.212,
Commercial Computer Software, Computer Software Documentation, and
Technical Data for Commercial Items are licensed to the U.S. Government
under vendor's standard commercial license.
The information contained herein is subject to change without notice.
The only warranties for HP products and services are set forth in the
express warranty statements accompanying such products and services.
Nothing herein should be construed as constituting an additional
warranty. HP shall not be liable for technical or editorial errors or
omissions contained herein.
Intel and Itanium are trademarks or registered trademarks of Intel
Corporation or its subsidiaries in the United States and other
countries.
UNIX is a registered trademark of The Open Group.
Portions of the ANSI C++ Standard Library have been implemented using
source licensed from and copyrighted by Rogue Wave Software, Inc. All
rights reserved.
Information pertaining to the C++ Standard Library has been edited and
reprinted with permission of Rogue Wave Software, Inc. All rights
reserved.
Portions copyright 1994-2007 Rogue Wave Software, Inc.
1 Introduction
This document contains the release notes for HP C++ V7.3
for OpenVMS Industry Standard 64 (I64) for Integrity Servers. The HP C++ product requires OpenVMS I64 Version
8.2-1 or higher.
The release notes for previous HP C++ versions are also included:
- See Sections 5 and 6 for the HP C++ V7.2
compiler and library release notes, respectively.
- See Section 7 for the HP C++ V7.1 compiler release notes, which
describe the new features, differences, and restrictions of the C++
V7.1 compiler for I64 systems over the C++ V6.5 compiler for Alpha
systems.
- See Section 8 for the HP C++ V7.1 release notes for the standard
library, language run-time support library, and class library.
2 Enhancements,
Changes, and Problems Corrected in the V7.3 Compiler
HP C++ V7.3 is largely a bug-fix release of the compiler,
although it does contain some significant new features including
multiple version support, new exception processing mode
pure_unix
, new command line qualifier /EXPORT_SYMBOLS, and an
unsupported/experimental mechanism for generating a customized
machine_code listing. The following describes these features along with
problems fixed and restrictions in this version.
3 Known Problems in
V7.3
The following are known problems in this release of the compiler:
- The
#pragma extern_model
directive does not support the alignment options
PAGE
and
16
.
- The compiler might emit an erroneous BADANSIALIASn message.
In
some situations the compiler's loop unrolling optimization can generate
memory accesses in the code stream that never actually execute at
run-time, but that would violate the ANSI Aliasing rules if they did
occur. In such a situation, the compiler might emit an erroneous
BADANSIALIASn message, where n is a number or is omitted. If the
violations take place only in machine instructions that will not
execute at run-time, these messages can be safely ignored. To
determine whether or not particular instances of a BADANSIALIASn
message are erroneous, recompile the module with the /OPT=UNROLL=1
qualifier. Any BADANSIALIASn messages that disapper under that
qualifier can be safely ignored, so you may want to add appropriate
#pragma message
directives to the source, localized to the specific source lines known
to be safe. This is preferable to disabling the message for the whole
compilation, since in all other cases the message indicates a real
potential for code generation that will not work as intended. And this
is generally preferable to disabling the ANSI_ALIAS or loop unrolling
optimizations, since that would likely degrade performance, although
the amount of degradation is not predictable, and in unusual cases it
might even improve performance. As always when making changes to
performance-critical code, it is best to measure the impact.
4 Enhancements, Changes,
and Problems Corrected in the V7.3 C++ Standard Library
The following problems are fixed in this version of the C++ Library:
- As described in
code_example(<http://issues.apache.org/jira/browse/STDCXX-397>),
__introsort_loop() function in code_example(<algorithm.cc>)
header has a bug which, for some input sequences, can adversely affect
performance of std::sort. See the Apache tracker for the issue
STDCXX-397 at URL above for more details.
The bug has been fixed.
However, for some input sequences, the fix can change the behaviour of
std::sort with regard to the relative order in which elements that have
equivalent ordering are placed into the sorted sequence. While this
change in behaviour is permissible because, unlike std::stable_sort,
std::sort does not guarantee any particular relative order of elements
having equivalent ordering, to avoid breaking applications that rely on
existing behaviour of std::sort, the fix is conditionalized with
__RW_FIX_APACHE_STDCXX_397 macro and is in effect only when the program
is compiled with this macro defined. [L2028]
- When compiled in standard GNU mode, the library now defines the
_RWSTD_NO_IMPLICIT_INCLUSION macro which causes library headers to
#include
their respective template definition files. This is necessary because
in standard GNU mode, implicit inclusion is disabled.
Before this
change, the program below would link with undefined symbol when
compiled in standard GNU mode:
#include <vector>
int main() {
std::vector<int> v;
v.push_back(0);
}
|
- According to section 27.6.1.3 [lib.istream.unformatted] of the C++
Standard, the following get member functions of the std::basic_istream
class should call setstate(failbit) if no characters have been stored,
as is the case for an empty line. While on I64 systems the functions
set failbit, on Alpha systems they do not:
istream_type& get(char_type *s, streamsize n, char_type delim);
istream_type& get(char_type *s, streamsize n);
|
See Section 8.4.5 for more information.
5 Release Notes for the V7.2 C++ Compiler
This section describes enhancements, changes, and problems corrected in
the C++ Version 7.2 compiler for I64 systems.
5.1 New Name Mangling/Prefixing Requires Recompile from Source
Note
The V7.2 compiler generates different mangled names from V7.1 for user
code. For 32-bit (default) compilations, V7.2 prefixes mangled names
with "CX3$", where V7.1 used "CXX$". C++ library names remain
unchanged, using the "CXXL$" prefix for 32-bit code. Applications built
with the V7.1 compiler must be fully-recompiled from source when moving
to V7.2. An application containing both "CXX$" and "CX3$" prefixed
names will not work correctly.
|
The introduction of 64-bit pointer support, described later, uncovered
some errors in the names generated by the V7.1 compiler that could
introduce incorrect run-time behaviors in standard-conforming programs
without any diagnostic. These behaviors could range anywhere from
harmless, to subtle, to access violations - and they are very difficult
to diagnose. Basically, the names generated for certain globals such as
initialization guard variables, vtables, and RTTI information used to
identify exceptions embed the names of types. Type names must always be
treated as case-sensitive in either C or C++. The V7.1 compiler
erroneously treated these names, if they happened to be less than
32-characters long, as being subject to the
/NAMES=
command-line qualifier, which by default uppercases them. In addition,
some of these names were not being given the facility prefix of "CXX$",
even though they were compiler-generated and not explicitly present in
the source code.
Because the I64 implementation uses object module "group sections"
(sometimes called comdats) to enforce the C++ "one definition" rule, a
mismatch in generated names usually results in more than one definition
for the same source entity without any diagnostic; whereas on OpenVMS
Alpha or in languages other than C++, a mismatch usually results in a
link-time diagnostic for an unresolved reference.
V7.1 was the initial release of the I64 compiler, and the effects of
mismatches caused by the V7.1 naming bugs can be very subtle and
difficult to diagnose. And it was important to make the mangled names
produced by V7.2 for 64-bit compilations not only correct but identical
to the names it produces for 32-bit compilations (except for the prefix
that distinguishes the pointer-size model). Therefore it was decided to
change the default prefix for 32-bit compilations in order to
distinguish object code that could contain the naming bugs (prefixed by
"CXX$") from object code that does not contain the naming bugs
(prefixed by "CX3$").
Applications that are linked from object modules against the C++
library shareables should not be affected when fully recompiled from
source using the new compiler and relinked.
Shareable images built from 32-bit C++ object modules would not
generally have universal symbols prefixed by the compiler's default
prefix, but rather they would normally use
#pragma extern_prefix
to give their universals their own namespace (or export only C-linkage
names, which are unchanged in V7.2). Users of such libraries would be
unaffected unless one or more universals they use actually were
affected by a naming bug. From experience with the C++ libraries this
is thought to be relatively uncommon. And in that case, the build of
the shareable image would fail when first built from object modules
compiled by the new compiler, because correcting the naming bug would
change the name of such a symbol. The library provider would then need
to change the symbol vector to provide the new name as a universal, and
alias the old name to it, which would again leave users of the library
unaffected regardless of whether they compiled with the old or new
compiler.
For shareable images built from object modules compiled by V7.1 that
did not use
#pragma extern_prefix
, but instead directly exported symbols prefixed by "CXX$" (or exported
erroneously unprefixed mangled names, which can be recognized as those
beginning with "_Z"), the link would also fail when built from objects
produced by V7.2. But in this case all of the symbol vector entries
would fail because the prefixes would be different. A solution would be
a global edit to the options file to change all of the "CXX$" prefixes
to "CX3$", and prepend "CX3$" to all symbols beginning with "_Z", and
relink. Failures in the relink would identify symbols that were
affected by the naming bugs, and those would need to be corrected as in
the preceding paragraph. Finally, aliases would need to be added from
the original names to the new names to make the shareable usable to
code produced by either V7.1 or V7.2 compilers.
For code that must link against object modules or shareable images that
cannot be recompiled from source, and which contain names affected by
the naming bugs (note this does *not* include the C++ libraries), the
simplest soulution is to use the V7.1 compiler if any such code needs
to be recompiled. If that is not feasible, unsupported switches may be
available from your support contact to ease this situation.
The need to avoid mixing V7.1 32-bit object modules with V7.2 32-bit
object modules cannot be over-emphasized - compiling one module with
V7.2 requires full recompilation from source of all object modules. The
primary purpose of changing the default prefix is to make mixing easy
to detect by examining the link map: if the map contains both "CXX$"
names and "CX3$" names, the modules containing "CXX$" names need to be
recompiled by the new compiler.
5.2 64-bit Runtime Libraries
The runtime libraries for HP C++ ship with the OpenVMS operating
system. This compiler kit adds support for 64-bit pointers, which
requires the 64-bit runtime libraries be available. Those new libraries
will ship with a future release of the OpenVMS operating system. A
patch kit for the ICXXL component of the operating system is available
which provides the new libraries for older versions of the operating
system.
5.3 64-bit Pointer Support
This version of the compiler adds support for 64-bit pointers. This
support is compatible with the 64-bit pointer support in the OpenVMS
Alpha C++ and C compilers. It supports the same /POINTER_SIZE
command-line qualifier, the
__INITIAL_POINTER_SIZE
predefined macro, and the same pragmas (
#pragma pointer_size
and
#pragma required_pointer_size
). However, the basic model for how and where pointers with a size
different from the default size (the size specified by the command-line
qualifier) can be declared and used in the language is considerably
more limited than it is in the other compilers.
Note
Limitations on the use of non-default-sized pointers are not generally
diagnosed or enforced by the compiler. Programs that do not follow the
model of mixed-size pointer usage outlined below are likely to fail at
run-time without any compile-time diagnostic.
|
The best-supported model of 64-bit pointer usage is when the command
line uses the /POINTER_SIZE=64 qualifier, called a 64-bit compilation.
In that case the entire C++ program is considered to use 64-bit
addressing, with a few exceptions made to permit the use of data
structures containing 32-bit pointers that are needed to communicate
with OpenVMS services and other non-C++ libraries. Such data structures
naturally contain only pointers to POD types, and the functions that
operate on those types naturally have extern "C" linkage. The
declarations of those data structures and functions reside in header
files, and those header files are coded to use the
__INITIAL_POINTER_SIZE
macro and the pointer_size pragmas to ensure that they use
appropriately-sized pointers regardless of the compilation mode. Except
for those declarations, all addresses, pointers, and references in a
C++ program compiled with /POINTER_SIZE=64, are considered to be 64-bit
types, and all C++ "new" operators allocate data from a 64-bit heap.
If the command line specifies the /POINTER_SIZE=32 qualifier, then it
is a 32-bit compilation, and the only use of 64-bit pointers can be
pointers to POD types provided by calls to _malloc64(), or obtained
from other non-C++ code.
While it is possible to use
#pragma pointer_size 32
to declare 32-bit pointers explicitly within a 64-bit compilation, the
region of source code covered by such pragmas should be made as small
as possible, and preferably confined just to typedefs for pointer types
that must be 32-bit pointers. In general, the source region should not
contain class definitions for non-POD types, template declarations,
declarations of functions that have C++ linkage, or executable code.
This differs significantly from C++ for OpenVMS Alpha, which permits
C++ classes to be defined with 32-bit pointers in a 64-bit compilation.
Another significant difference is that the Alpha compiler attempts to
determine the "best" pointer size to use when determining the type of
an "address-of" expression. It uses the fact that on OpenVMS, C++
declared objects (either stack-based or static-extent) always have
addresses that fit in 32-bits; and for expressions that involve
pointer-dereferencing it uses the width of the pointer that was
dereferenced as the width of the pointer type given to the expression.
This usually allows address-of expressions to be assigned to pointers
without casting. In 64-bit mode, the I64 compiler assumes that an
address-of expression will yield a 64-bit pointer unless its operand is
a dereference of a 32-bit pointer, and so it may issue spurious
NARROWPTR
warnings for assignments of address-of expressions to 32-bit pointers;
an explicit cast to the correct 32-bit pointer type is needed to
silence the warning. As a special case, 64-bit pointer-to-function
values may be assigned to 32-bit pointer-to-function objects without
complaint (the value of a function pointer always fits in 32-bits on
OpenVMS).
Neither Alpha nor I64 compilers include the pointer size when forming
mangled names, so naturally it is not possible to overload functions
based only on differences in pointer size: the Alpha compiler reports
this explicitly at compile time when possible, but on I64 it will just
produce conflicting multiple definitions. In general, if a 32-bit
pointer type needs to appear in a function prototype in a 64-bit
compilation, it is a good practice to define a
struct
type just to hold the pointer, and pass the
struct
instead of the pointer type.
Except for names declared with extern "C" linkage, the I64 compiler
produces completely disjoint external symbols in the object modules for
64-bit compilations and 32-bit compilations. For 64-bit compilations,
user-declared names are prefixed by "CX6$" (instead of "CX3$"), and
library names are prefixed by "CX6L$" (instead of "CXXL$"). Following
the prefix, names are mangled identically in the two modes, so a given
source declaration will produce the same name in the object module
differing only by the prefix if compiled in different modes. So while
it is possible to include both 32-bit and 64-bit compilations in the
same program, they will not interact with each other except through
extern "C" linkage names.
5.3.1 Pointer_Size Control Differences
Although the syntax and use of pointer_size controls are the same for
Alpha and I64, and most programs that work correctly on Alpha should
also work on I64 without change, the differences in the compiler's
model of how the pointer_size controls work on the two platforms can
affect behavior, particularly in programs that create pointers to C++
objects (non-POD types) having a size that differs from the setting of
the /POINTER_SIZE command-line qualifier, or that apply the
sizeof
operator to expressions that have a pointer type:
- On Alpha systems, the compiler uses an object model that generally
supports the declaration and use of both 64-bit and 32-bit pointers,
and the
#pragma pointer_size
directives can be placed at most any point in the source code. The
pointer_size in effect at any given point in the source generally
influences both the size of pointers created for explicit pointer
declarations, and also the size of pointers generated by the compiler
to implement various language constructs. There are some restrictions
such as no overloading of functions based on pointer size, but
generally speaking the size of individual pointer types and the current
setting of the pointer_size from the #pragmas is taken into account at
fairly low levels, and pointers to C++ objects (non-POD types) can be
of either size. Modules compiled with one setting of /POINTER_SIZE can
in some cases interoperate with code compiled with a different setting,
although this is not a good practice. And in general, the result of the
address-of operator (&) has a pointer type whose size reflects the
current pointer size.
- On I64 systems, the /POINTER_SIZE command-line qualifier plays a
much larger role than on Alpha systems. This qualifier chooses between
two different, incompatible, binary models for C++ code generation.
Functions with C++ linkage produced under /POINTER_SIZE=64 cannot be
called from functions with C++ linkage produced under /POINTER_SIZE=32
(the default with no /POINTER_SIZE qualifier), and vice-versa.
And
64-bit compilations use a completely separate implementation of the C++
libraries from 32-bit compilations. Furthermore, the /POINTER_SIZE
qualifier on I64 controls much more completely the compiler's
determination of pointer size throughout the compilation. Basically,
the only pointer types that are given a size different from the size
specified on the command line are pointer types explicitly declared
with the "*" declarator syntax in the context of a
#pragma pointer_size
. And the only pointer types that should be given a pointer_size
different from that specified by the command line are pointers to POD
types. Pointers to non-POD types, as well as all implicitly-generated
pointer type are assumed to have the size specified by the command
line. Of special note, the address-of operator (&) generally
produces a pointer whose size is based on the size specified by the
command line. This is a difference from Alpha. The one exception is
when the operator is applied to a pointer dereference, in which case
the result is the size of the dereferenced pointer. This exception
matches the Alpha behavior. The compiler does not diagnose the use
of pointers having a size different from the command-line size that
point to non-POD types; in some situations such pointers may produce
intended results, but in general their use may cause unexpected
behaviors or access violations at run-time.
The following example program illustrates some of these differences:
#include <stdio.h>
#if __INITIAL_POINTER_SIZE == 64
#define CMD "/POINT=64"
#else
#define CMD "/POINT=32"
#endif
#if __ALPHA
#define MACH "Alpha"
#else
#define MACH "I64 "
#endif
void main(void) {
printf(MACH CMD ":\n");
{
#pragma __required_pointer_size 64
#define SZ " #pragma 64: "
int i;
printf(SZ "sizeof(&i) = %d.\n", sizeof(&i));
printf(SZ "value of &i = 0x%016llx.\n", (long long)&i);
printf(SZ "sizeof(&\"str\"[1]) = %d.\n", sizeof(&"str"[1]));
printf(SZ "value of &\"str\"[1] = 0x%016llx.\n", (long long)&"str"[1]);
const char array[] = "str";
printf(SZ "sizeof(&array[1]) = %d.\n", sizeof(&array[1]));
printf(SZ "value of &array[1] = 0x%016llx.\n", (long long)&array[1]);
printf(SZ "sizeof(new int) = %d.\n", sizeof(new int));
printf(SZ "value of (new int) = 0x%016llx.\n", (long long)new int);
char *newcp = new char[2];
printf(SZ "sizeof(newcp) = %d.\n", sizeof(newcp));
printf(SZ "value of newcp = 0x%016llx.\n", (long long)newcp);
printf(SZ "sizeof(&newcp[1]) = %d.\n", sizeof(&newcp[1]));
printf(SZ "value of &newcp[1] = 0x%016llx.\n", (long long)&newcp[1]);
}
printf("\n" MACH CMD ":\n");
{
#pragma __required_pointer_size 32
#undef SZ
#define SZ " #pragma 32: "
int i;
printf(SZ "sizeof(&i) = %d.\n", sizeof(&i));
printf(SZ "value of &i = 0x%016llx.\n", (long long)&i);
printf(SZ "sizeof(&\"str\"[1]) = %d.\n", sizeof(&"str"[1]));
printf(SZ "value of &\"str\"[1] = 0x%016llx.\n", (long long)&"str"[1]);
const char array[] = "str";
printf(SZ "sizeof(&array[1]) = %d.\n", sizeof(&array[1]));
printf(SZ "value of &array[1] = 0x%016llx.\n", (long long)&array[1]);
printf(SZ "sizeof(new int) = %d.\n", sizeof(new int));
printf(SZ "value of (new int) = 0x%016llx.\n", (long long)new int);
char *newcp = new char[2];
printf(SZ "sizeof(newcp) = %d.\n", sizeof(newcp));
printf(SZ "value of newcp = 0x%016llx.\n", (long long)newcp);
printf(SZ "sizeof(&newcp[1]) = %d.\n", sizeof(&newcp[1]));
printf(SZ "value of &newcp[1] = 0x%016llx.\n", (long long)&newcp[1]);
}
}
|
Output on I64 with /POINTER=32
Note that all of the pointer sizes, except for the explicitly declared
64-bit pointer variable, and the address of an array element access
made through that pointer variable, reflect the command-line setting:
$ pipe cxx/point=32 pointers ; cxxlink pointers ; run pointers
I64 /POINT=32:
#pragma 64: sizeof(&i) = 4.
#pragma 64: value of &i = 0x000000007acffb28.
#pragma 64: sizeof(&"str"[1]) = 4.
#pragma 64: value of &"str"[1] = 0x0000000000040001.
#pragma 64: sizeof(&array[1]) = 4.
#pragma 64: value of &array[1] = 0x000000007acffb11.
#pragma 64: sizeof(new int) = 4.
#pragma 64: value of (new int) = 0x00000000001e0b70.
#pragma 64: sizeof(newcp) = 8.
#pragma 64: value of newcp = 0x00000000001e0b50.
#pragma 64: sizeof(&newcp[1]) = 8.
#pragma 64: value of &newcp[1] = 0x00000000001e0b51.
I64 /POINT=32:
#pragma 32: sizeof(&i) = 4.
#pragma 32: value of &i = 0x000000007acffb30.
#pragma 32: sizeof(&"str"[1]) = 4.
#pragma 32: value of &"str"[1] = 0x0000000000040001.
#pragma 32: sizeof(&array[1]) = 4.
#pragma 32: value of &array[1] = 0x000000007acffb21.
#pragma 32: sizeof(new int) = 4.
#pragma 32: value of (new int) = 0x00000000001e3690.
#pragma 32: sizeof(newcp) = 4.
#pragma 32: value of newcp = 0x00000000001e3670.
#pragma 32: sizeof(&newcp[1]) = 4.
#pragma 32: value of &newcp[1] = 0x00000000001e3671.
|
Output on Alpha with /POINTER=32
Note that all of the pointer sizes, except for the result type of the
"new" operator, reflect the pragma setting:
$ pipe cxx/point=32 pointers ; cxxlink pointers ; run pointers
Alpha/POINT=32:
#pragma 64: sizeof(&i) = 8.
#pragma 64: value of &i = 0x000000007ad8f9e0.
#pragma 64: sizeof(&"str"[1]) = 8.
#pragma 64: value of &"str"[1] = 0x00000000000145e1.
#pragma 64: sizeof(&array[1]) = 8.
#pragma 64: value of &array[1] = 0x000000007ad8f9d9.
#pragma 64: sizeof(new int) = 4.
#pragma 64: value of (new int) = 0x000000000007f310.
#pragma 64: sizeof(newcp) = 8.
#pragma 64: value of newcp = 0x0000000000083350.
#pragma 64: sizeof(&newcp[1]) = 8.
#pragma 64: value of &newcp[1] = 0x0000000000083351.
Alpha/POINT=32:
#pragma 32: sizeof(&i) = 4.
#pragma 32: value of &i = 0x000000007ad8f9d0.
#pragma 32: sizeof(&"str"[1]) = 4.
#pragma 32: value of &"str"[1] = 0x00000000000145e1.
#pragma 32: sizeof(&array[1]) = 4.
#pragma 32: value of &array[1] = 0x000000007ad8f9c9.
#pragma 32: sizeof(new int) = 4.
#pragma 32: value of (new int) = 0x0000000000083cb0.
#pragma 32: sizeof(newcp) = 4.
#pragma 32: value of newcp = 0x0000000000083cc0.
#pragma 32: sizeof(&newcp[1]) = 4.
#pragma 32: value of &newcp[1] = 0x0000000000083cc1.
|
Output on I64 with /POINTER=64
Note that all of the pointer sizes, except the explicitly declared
32-bit pointer variable, and the address of an array element access
made through that pointer variable, reflect the command-line setting.
The warning message identifies a real problem where the 64-bit pointer
produced by "new" does not fit into the 32-bit pointer variable
newcp, and the value of newcp reflects this by being
sign-extended:
$ pipe cxx/point=64 pointers ; cxxlink pointers ; run pointers
char *newcp = new char[2];
.................^
%CXX-W-MAYLOSEDATA, cast from long pointer to short pointer will lose data.
at line number 54 in file DISK$:[DIR]POINTERS.CXX;1
%ILINK-W-COMPWARN, compilation warnings
module: POINTERS
file: DISK$:[DIR]POINTERS.OBJ;1
I64 /POINT=64:
#pragma 64: sizeof(&i) = 8.
#pragma 64: value of &i = 0x000000007acffb28.
#pragma 64: sizeof(&"str"[1]) = 8.
#pragma 64: value of &"str"[1] = 0x0000000000040001.
#pragma 64: sizeof(&array[1]) = 8.
#pragma 64: value of &array[1] = 0x000000007acffb11.
#pragma 64: sizeof(new int) = 8.
#pragma 64: value of (new int) = 0x000000008009c010.
#pragma 64: sizeof(newcp) = 8.
#pragma 64: value of newcp = 0x000000008009c030.
#pragma 64: sizeof(&newcp[1]) = 8.
#pragma 64: value of &newcp[1] = 0x000000008009c031.
I64 /POINT=64:
#pragma 32: sizeof(&i) = 8.
#pragma 32: value of &i = 0x000000007acffb30.
#pragma 32: sizeof(&"str"[1]) = 8.
#pragma 32: value of &"str"[1] = 0x0000000000040001.
#pragma 32: sizeof(&array[1]) = 8.
#pragma 32: value of &array[1] = 0x000000007acffb21.
#pragma 32: sizeof(new int) = 8.
#pragma 32: value of (new int) = 0x000000008009c050.
#pragma 32: sizeof(newcp) = 4.
#pragma 32: value of newcp = 0xffffffff8009c070.
#pragma 32: sizeof(&newcp[1]) = 4.
#pragma 32: value of &newcp[1] = 0xffffffff8009c071.
|
Output on Alpha with /POINTER=64
Note that all of the pointer sizes reflect the pragma setting, except
for the result type of the "new" operator. The warning message
identifies the same problem identified on I64, and the value of
newcp similarly reflects this by being sign-extended:
$ pipe cxx/point=64 pointers ; cxxlink pointers ; run pointers
char *newcp = new char[2];
.................^
%CXX-W-MAYLOSEDATA, cast from long pointer to short pointer will lose data.
at line number 54 in file DISK$:[DIR]POINTERS.CXX;1
%LINK-W-WRNERS, compilation warnings
in module POINTERS file DISK$:[DIR]POINTERS.OBJ;1
Alpha/POINT=64:
#pragma 64: sizeof(&i) = 8.
#pragma 64: value of &i = 0x000000007ad8f9e0.
#pragma 64: sizeof(&"str"[1]) = 8.
#pragma 64: value of &"str"[1] = 0x00000000000145e1.
#pragma 64: sizeof(&array[1]) = 8.
#pragma 64: value of &array[1] = 0x000000007ad8f9d9.
#pragma 64: sizeof(new int) = 8.
#pragma 64: value of (new int) = 0x0000000080000010.
#pragma 64: sizeof(newcp) = 8.
#pragma 64: value of newcp = 0x0000000080000030.
#pragma 64: sizeof(&newcp[1]) = 8.
#pragma 64: value of &newcp[1] = 0x0000000080000031.
Alpha/POINT=64:
#pragma 32: sizeof(&i) = 4.
#pragma 32: value of &i = 0x000000007ad8f9d0.
#pragma 32: sizeof(&"str"[1]) = 4.
#pragma 32: value of &"str"[1] = 0x00000000000145e1.
#pragma 32: sizeof(&array[1]) = 4.
#pragma 32: value of &array[1] = 0x000000007ad8f9c9.
#pragma 32: sizeof(new int) = 8.
#pragma 32: value of (new int) = 0x0000000080000050.
#pragma 32: sizeof(newcp) = 4.
#pragma 32: value of newcp = 0xffffffff80000070.
#pragma 32: sizeof(&newcp[1]) = 4.
#pragma 32: value of &newcp[1] = 0xffffffff80000071.
|
5.3.2 Mixed Pointer-Size Allocators
Mixed pointer-size allocators are placement-new allocators accepting
addr_32 and addr_64 parameters. They are documented in Chapter 9.1.2
Memory Allocators in the HP C++ User's Guide for OpenVMS
Systems. On both OpenVMS Alpha and I64 systems, these allocators
are implemented in the
<newext.hxx>
header file.
Note the following differences between mixed pointer-size allocators on
OpenVMS Alpha and I64 systems:
- On Alpha systems, addr_32_space and addr_64_space enums are in the
global namespace.
On I64 systems, they are in the namespace
__deccxx. The
<newext.hxx>
header has the 'using namespace __deccxx;' directive; so, in general,
there is no need to specify a fully qualified name, and the code from
an Alpha system can be compiled on an I64 system without any changes.
However, if an ambiguity arises, a fully qualified name can be
specified on an I64 system: new(__deccxx::addr_32_space) or
new(__deccxx::addr_64_space).
- On I64 systems, the new(addr_64_space) allocator can be used only
in compilations with /POINTER=LONG, where it returns a long pointer to
memory allocated in 64-bit space.
On I64 systems in compilations
with /POINTER=SHORT, this allocator returns a NULL pointer, and the
compiler issues the ADDR64NOT diagnostics. See the example below. Also,
on I64 systems in compilations with /POINTER=SHORT, the size of the
pointer (having a zero value) returned by this allocator is 4. On
Alpha systems, the new(addr_64_space) allocator returns a long pointer
to memory allocated in 64-bit space in compilations with both
/POINTER=SHORT and /POINTER=LONG. On I64 systems, the
new(addr_64_space) allocator is retained only to allow code compiled on
Alpha systems with /POINTER=LONG to be compiled on I64 with
/POINTER=LONG without any changes.
x.cxx
below demonstrates the difference in behavior of the new(addr_64_space)
allocator on I64 and Alpha systems. Note that the behavior of the
new(addr_32_space) allocator is the same on both platforms.
x.cxx
-----
#include <newext.hxx>
#include <stdio.h>
main() {
__char_ptr32 x;
__char_ptr64 y;
x = new (addr_32) char;
y = new (addr_64) char;
printf("x = %llx, y = %llx\n", x, y);
printf("sizeof(new(addr_32)) = %d, sizeof(new(addr_64)) = %d\n",
sizeof(new(addr_32) char), sizeof(new(addr_64) char));
}
The output on Alpha system:
---------------------------
$ pipe cxx/pointer=short x.cxx ; cxxlink x.obj ; run x.exe
x = 78690 y = 80000010
sizeof(new(addr_32)) = 4 sizeof(new(addr_64)) = 8
$ pipe cxx/pointer=long x.cxx ; cxxlink x.obj ; run x.exe
x = 78690 y = 80000010
sizeof(new(addr_32)) = 4 sizeof(new(addr_64)) = 8
$
The output on I64 system:
--------------------------
$ pipe cxx/pointer=long x.cxx ; cxxlink x.obj ; run x.exe
x = 1f48e0 y = 8009c010
sizeof(new(addr_32)) = 4 sizeof(new(addr_64)) = 8
$ pipe cxx/pointer=short x.cxx ; cxxlink x.obj ; run x.exe
y = new (addr_64) char;
...........^
%CXX-W-ADDR64NOT, Use of std::addr_64 in placement new requires
/POINTER_SIZE=LONG on this platform.
sizeof(new (addr_32) char), sizeof(new (addr_64) char));
.................................................^
%CXX-W-ADDR64NOT, Use of std::addr_64 in placement new requires
/POINTER_SIZE=LONG on this platform.
x = 1f88d0 y = 0
sizeof(new(addr_32)) = 4 sizeof(new(addr_64)) = 4
$
|
5.4 Other Enhancements, Changes, and Problems Corrected
- Variadic macros are now supported. This feature allows macros to
take a variable number of arguments. It was added to Version 6.4 of the
HP C Compiler and is supported by a number other C and C++ compilers.
This feature is available only when the value of the /STANDARD
qualifier is RELAXED (the default), MS, or GNU.
- This version of the C++ compiler contains support for generation of
a new section type in the object file that maps mangled names to their
original unmangled form. Future versions of the linker will take
advantage of this feature by using the demangled spelling of an
identifier name for its error messages. In addition, the linker will be
able to generate a new section in the linker map that shows mangled
names and their corresponding unmangled orginal name.
- Prologue and epilogue file header processing is now supported in HP
C++.
- The
__FUNCTION__
identifier is added.
__FUNCTION__
is a predefined pointer to
char
defined by the compiler, which points to the name of the function as it
appears in the source program.
__FUNCTION__
is same as
__func__
of C99.
- Previously, the propagation of a C++ exception out of a thread's
start routine did not result in cxxl$terminate() being called. A
solution for the problem is available on OpenVMS I64 Version V8.2-1 and
higher. For V8.2-1, it requires pthreads library patch
VMS821I_PTHREAD-V0300. For V8.3, it requires pthreads library patch
VMS83I_PTHREAD-V0100.
- A problem has been corrected in the implicit include processing.
The implicit inclusion will no longer select files such as ".C" or
".CXX" (where these files have no file name portion).
- In the /STANDARD=STRICT mode of compilation, the compiler used to
issue a diagnostic with the severity of error for NULL reference
expression within a
sizeof
expression. The severity of the diagnostic is now an informational.
- The /TEMPLATE_DEFINE qualifier now requires an option.
-
#pragma module module-name [module-ident | "module-ident"]
If the module-name is too long:
- A warning is generated if /NAMES=TRUNCATED is specified.
- There is no warning if /NAMES=SHORTEN is specified.
A shortened
external name incorporates all the characters in the original name. If
two external names differ by as little as one character, their
shortened external names will be different. If the optional
module-ident or "module-ident" is too long, a warning
is generated.
The default module-name is the filename of the first
source file. The default module-ident is "V1.0" They are
treated as if they were specified by a
#pragma module
directive. If the module-name is longer than 31 characters:
- and /NAMES=TRUNCATE is specified, truncate to 31 characters, or
less if the 31st character is within a Universal Character Name.
- and /NAMES=SHORTENED is specified, shorten the module-name
to 31 characters using the same special encoding as other external
names.
Lowercase characters in the module-name are converted to
upper case only if /NAMES=UPPERCASE is specified. A
module-ident that is longer than 31 characters is treated as
if /NAMES=(TRUNCATED,AS_IS) were applied, truncating it to 31
characters, or less if the 31st character is within a Universal
Character Name. The default module-name comes from the
source file name which always appears in the listing header. The
module-name (and ident) appear in the listing header only if
they come from a
#pragma module
directive or differ from the default.
- To use the LIB$INITIALIZE feature explicitly in either C or C++, a
compilation should contain a reference to a parameterless void function
named LIB$INITIALIZE, and provide a statically-initialized list of
32-bit pointers to the functions to be called in a psect named
LIB$INITIALIZE with appropriate attributes. The following sample source
code shows how this can be done. For simplicity in using both
languages, this example gives the initialization functions extern "C"
linkage.
/* Example to set up LIB$INITIALIZE usage by creating a reference
** to the LIB$INITIALIZE function, and an initialized list of
** functions to be called in the LIB$INITIALIZE psect.
*/
#ifdef __cplusplus
extern "C" {
#endif
/* Declarations for initialization functions. */
extern void some_init_function(void);
extern void some_other_init_function(void);
/* etc, e.g. other declarations might come from header files */
/* Use 32-bit pointers */
#if __INITIAL_POINTER_SIZE
#pragma pointer_size save
#pragma pointer_size 32
#endif
/* Create a reference to the LIB$INITIALIZE function. */
extern void LIB$INITIALIZE(void);
extern void (*unused_global_variable_1)(void) = LIB$INITIALIZE;
/* Create an array of pointers to the init functions in the special
** LIB$INITIALIZE section.
*/
#pragma extern_model save
#pragma extern_model strict_refdef "LIB$INITIALIZE" gbl,noexe,nowrt,noshr,long
extern void (* const unused_global_variable_2[])() =
{
some_init_function
, some_other_init_function
/* etc, other functions to be called by LIB$INITIALIZE() */
};
#pragma extern_model restore
#if __INITIAL_POINTER_SIZE
#pragma pointer_size restore
#endif
#ifdef __cplusplus
}
#endif
/* End of example to set up LIB$INITIALIZE */
/* Begin executable test of LIB$INITIALIZE setup. */
#ifdef __cplusplus
extern "C" {
#endif
extern int printf(const char *, ...);
extern void some_init_function(void) {
printf("In some_init_function.\n");
}
extern void some_other_init_function(void) {
printf("In some_other_init_function.\n");
}
#ifdef __cplusplus
}
#endif
void main(void) {
printf("In main.\n");
}
/* Compile with either C or C++ on Alpha or I64, link and run.
** The output is:
** In some_init_function.
** In some_other_init_function.
** In main.
*/
|
5.5 Known Problems and Restrictions
- On I64 systems, the
#pragma inline
or
#pragma noinline
directives are not supported.
- On I64 systems, the
#pragma function
and
#pragma intrinsic
directives are ignored.
- On I64 systems, the intrinsic bit-counting functions
_leadz()
,
_trailz()
,
_popcnt()
, and
_poppar()
declared at the end of
<builtins.h>
are treated as intrinsic whether or not the header is included. Since
these function names begin with an underscore followed by a lowercase
letter, under the language standards they are reserved to the
implementation for use as identifiers with external linkage. So
programs that declare their own functions with any of these names are
not standard-conforming. However, the Alpha C++ compiler and the C
compiler for both Alpha and I64 support user-written functions with
these names as long as
<builtins.h>
is not included; or if it is included and followed by
#pragma function
directives for these names. The I64 C++ compiler will accept
user-defined functions with these names, but calls to them will
generally be treated as having the intrinsic behavior, which may
produce unpredictable results if the user declaration does not match
the intrinsic declaration.
- ANAL/OBJ on OpenVMS 8.2-1 and earlier will issue an error message
about an unknown section type that is now generated by this version of
the compiler:
%ANALYZE-E-ELF_UNKNWNSEC, Unrecognized Elf Section Type 60000007
|
Please ignore this message. This section is ignored by current
versions of the linker and ANAL/IMAGE and causes no harm.
- Debugging with optimized code is not supported.
6 Release Notes for the V7.2 C++ Standard Library
This section describes enhancements, changes, restrictions and problems
corrected for the V7.2 C++ Standard Library.
- While applications using the C++ library iostreams can be compiled
with the _LARGEFILE macro defined, the C++ library iostreams do not
support seeking to 64-bit file offsets. For more information on
_LARGEFILE macro see the HP C Run-Time Library Reference Manual for
OpenVMS Systems.
- The C++ Standard Library headers have been modified to allow
include-once compiler optimization. This reduces compilation time and
the size of the listing file.
- The std::numeric_limits.round_error() function has been corrected
to return a value corresponding to the dynamic rounding mode in effect
for the program. In particular, to determine the current dynamic
rounding mode, the std::numeric_limits.round_error() function now calls
C Run-Time Library function read_rnd().
- To comply with 21.2 - String classes [lib.string.classes] in the
C++ standard, declarations of the std::getline() function operating on
basic_istream have been moved from <istream> to <string>.
Accordingly, the definition of the std::getline() function operating on
basic_istream and accepting the delim parameter has been moved
from <istream.cc> to <string.cc>. This change is visible
only when using the standard iostreams.
- A problem has been corrected with the assignment operator of the
tree container not storing the comparison object of the container being
copied into the target container.
The tree container is the
underlying container for the map and set STL containers. Because of
this problem, after assigning one STL container object to another, the
target container would continue to use the comparison object it was
using before the assignment. It violates section 23.1.2 - Associative
containers [lib.associative.reqmts] of the C++ standard which states:
"When an associative container is constructed by passing a
comparison object the container shall not store a pointer or reference
to the passed object, even if that object is passed by reference. When
an associative container is copied, either through a copy constructor
or an assignment operator, the target container shall then use the
comparison object from the container being copied, as if that
comparison object had been passed to the target container in its
constructor."
- The C++ Standard Library header <vector> was modified to
expose std::vector<bool> overloads of relational operators only
when compiling with the __DECFIXCXXL1941 macro defined. These overloads
make it impossible to use relational operators on
vector<bool>::iterator types; see the code example below. That
the current C++ standard lists these overloads (section 23.2.5 - Class
vector<bool> [lib.vector.bool]) is considered to be a defect in
the standard. Some other implementations of STL do not provide these
overloads.
With std::vector<bool> overloads of all the
relational operators removed, the following program compiles. Before
the change, it would not compile.
#include <iterator>
#include <vector>
class D : public std::reverse_iterator<std::vector<bool>::iterator> {
};
int main(void)
{
D x, y;
if ( std::operator== <std::vector<bool>::iterator>(x,y) )
return 0;
if ( std::operator!= <std::vector<bool>::iterator>(x,y) )
return 0;
if ( std::operator< <std::vector<bool>::iterator>(x,y) )
return 0;
if ( std::operator<= <std::vector<bool>::iterator>(x,y) )
return 0;
if ( std::operator> <std::vector<bool>::iterator>(x,y) )
return 0;
if ( std::operator>= <std::vector<bool>::iterator>(x,y) )
return 0;
return 1;
}
|
- Specifying a C++ headers library and a C headers library using "+"
and the /LIB qualifier on the
cxx
command line, as in the following example, can cause the compiler to
fetch a C header file from the C headers library instead of a template
definition file from the C++ headers library:
cxx x.cxx+SYS$LIBRARY:CXXL$ANSI_DEF.TLB/LIB+SYS$LIBRARY:DECC$RTLDEF.TLB/LIB
|
This can happen if a C header file has the same filename as the C++
template definition file; for example, the
string.h
header file in the C headers library and
string.cc
template definition file in the C++ headers library.
7 Release Notes for the V7.1 C++ Compiler
This section describes the new features, differences, and restrictions
of the C++ V7.1 compiler for I64 systems over the C++ V6.5 compiler for
Alpha systems. See Section 8 for the release notes for the standard
library, language run-time support library, and class library.
This release of the compiler uses a new technology base that differs
substantially from both HP C++ for OpenVMS Alpha and HP C for OpenVMS
I64. Although a great deal of work has been done to make it highly
compatible with HP C++ for OpenVMS Alpha, there are a number of
differences that you will likely notice. Some of these differences are
temporary, some are changes that will be reflected in the next version
of the compiler for Alpha systems, and some are permanent. Among the
permanent differences are:
- Resource requirements
Programs will usually use more memory
both at compile time and at run time. See Section 7.3.1.
- Floating-point behaviors
The default is
/FLOAT=IEEE/IEEE_MODE=DENORM_RESULTS. Consistent use of qualifiers
across compilations is required. See Section 7.3.5.
- Simplified instantiation without repository. See Section 7.3.9.
- No inline assembly language. See Section 7.3.6.
- Removal of the CFRONT dialect (which will also be removed in the
next release of the C++ Alpha compiler).
- String literal type change.
For standards-compliance and link
compatiblity between compiler dialects, ordinary string literals now
have the type "array of const char" in all compiler dialects on I64
systems and on Alpha systems when compiling in /MODEL=ANSI mode.
When compiling in /MODEL=ARM mode on Alpha systems, string literals
are of type "array of char" in all compiler dialects.
7.1 Problems Fixed in V7.1
A problem has been corrected when using the common_block extern_model.
A temporary global symbol is no longer emitted when generating the data.
7.2 New Features in V7.1
The following new features and changes have been made since C++ Version
6.5 for OpenVMS Alpha systems.
7.2.1 cname Header Support
The C++ compiler implements section 17.4.1.2 - Headers [lib.headers]
"C++ Headers for C Library Facilities" of the C++ Standard. See also
Stroustrup's The C++ Programming Language, 3rd Edition
sections 9.2.2 and 16.1.2.
The implementation consists of 18
<cname>
headers defined in the C++ Standard:
<cassert> <cctype> <cerrno> <cfloat>
<ciso646> <climits> <clocale> <cmath>
<csetjmp> <csignal> <cstdarg> <cstddef>
<cstdio> <cstdlib> <cstring> <ctime>
<cwchar> <cwctype>
|
As required by the C++ standard, the
<cname>
headers define C names in the
std
namespace. In /NOPURE_CNAME mode, the names are also inserted into the
global namespace. See the description of the /[NO]PURE_CNAME compiler
qualifier.
The
<cname>
headers are located in the same TLB library that contains the C++
standard and class library headers: SYS$SHARE:CXXL$ANSI_DEF.TLB.
7.2.2 __HIDE_FORBIDDEN_NAMES Predefined in Strict ANSI Mode
When compiling in /STANDARD=STRICT_ANSI mode, the compiler predefines
the __HIDE_FORBIDDEN_NAMES macro, causing the C headers to expose only
those symbols that are defined by the ANSI C Standard 89. While this is
a change in behavior between C++ V6.5 for OpenVMS Alpha systems and C++
for I64 Systems, the new behavior is consistent with the behavior of
the C compiler in /STANDARD=ANSI89 mode.
As a result of this change, the following program would not compile on
an I64 system in /STANDARD=STRICT_ANSI mode (note that
fdopen
is not part of the ANSI C Standard 89).
#include <stdio.h>
void foo() {
fdopen(0,0);
}
|
7.2.3 /[NO]FIRST_INCLUDE Qualifier Added
The /[NO]FIRST_INCLUDE qualifier is added. It has the following format:
/[NO]FIRST_INCLUDE=(file[,...])
This qualifier includes the specified files before any source files. It
corresponds to the Tru64 UNIX
-FI
switch.
When /FIRST_INCLUDE=file is specified, file is
included in the source as if the line before the first line of the
source was:
If more than one file is specified, the files are included in their
order of appearance on the command line.
This qualifier is useful if you have command lines to pass to the C
compiler that are exceeding the DCL command-line length limit. Using
the /FIRST_INCLUDE qualifier can help solve this problem by replacing
lengthy /DEFINE and /WARNINGS qualifiers with
#define
and
#pragma message
preprocessor directives placed in a /FIRST_INCLUDE file.
The default is /NOFIRST_INCLUDE.
7.2.4 #pragma include_directory Added
The effect of each
#pragma include_directory
is as if its string argument (including the quotes) were appended to
the list of places to search that is given its initial value by the
/INCLUDE_DIRECTORY qualifier, except that an empty string is not
permitted in the pragma form.
The
#pragma include_directory
directive has the following format:
#pragma include_directory <string-literal>
|
This pragma is intended to ease DCL command-line length limitations
when porting applications from POSIX-like environments built with
makefiles containing long lists of -I options that specify directories
to search for headers. Just as long lists of macro definitions
specified by the /DEFINE qualifier can be converted to
#define
directives in a source file, long lists of places to search specified
by the /INCLUDE_DIRECTORY qualifier can be converted to
#pragma include_directory
directives in a source file.
Note that the places to search, as described in the help text for the
/INCLUDE_DIRECTORY qualifier, include the use of POSIX-style pathnames,
for example
"/usr/base"
. This form can be very useful when compiling code that contains
POSIX-style relative pathnames in
#include
directives. For example,
#include <subdir/foo.h>
can be combined with a place to search such as
"/usr/base"
to form
"/usr/base/subdir/foo.h"
, which will be translated to the filespec "USR:[BASE.SUBDIR]FOO.H"
This pragma can appear only in the main source file or in the first
file specified on the /FIRST_INCLUDE qualifier. Also, it must appear
before any
#include
directives.
7.2.5 Messages
There have been some changes in the /WARNINGS qualifier. These include
bug fixes and improved compatibility with the C compiler. Some changes
that might affect user compilations are:
- The /WARNINGS=ENABLE=ALL qualifier now enables all compiler
messages including informational-level messages.
- The /WARNINGS=INFORMATIONALS qualifier continues to enable most
informationals, but we recommend that /WARNINGS=ENABLE=ALL be used
instead
- Using /WARNINGS=INFORMATIONALS=<tag> no longer enables all
other informational messages.
The move from Alpha systems to I64 systems will cause some minor
differences in certain compiler diagnostics that are signaled from the
code generator. As a result, diagnostics for unreachable code and
fetches of uninitialized variables might be different on the two
platforms. In addition to a change in message text, some conditions
detected on one platform might not be detected on the other.
7.2.6 New Front End
A new C++ front end provides improved conformance to the C++
International Standard.
7.3 I64 Differences
This section describes differences between the C++ compiler on I64
systems and Alpha systems.
7.3.1 Quotas
The C++ compiler for I64 systems is built from a different code base
than the C++ compiler for Alpha systems, and that code base is larger
than the code base for Alpha. Also, I64 images tend to be somewhat
larger than Alpha images in general. Image size mostly affects
working-set size and the amount of pagefile quota needed to execute an
image without exhausting virtual memory. If you find that programs that
compile and run successfully on Alpha run out of memory on I64 systems
(either during compilation or when run), you probably need to increase
your pagefile quota. There are no specific guidelines at this time. You
might start by doubling the quota that was sufficient on Alpha, and
then use a "binary-search" approach to arrive at a better quota value
for I64 systems (doubling again, or halving the increment, until your
biggest programs and compilations have just enough memory, and then
adding an appropriate safety margin).
7.3.2 Dialect Changes
The following dialect changes have been made:
- Support for /STANDARD=CFRONT has been retired.
- Some of the compiler dialects (options to the /STANDARD qualifier)
have been updated to reflect the most recent behaviors of the compilers
that the dialect is attempting to match. Other changes involve the
removal of less significant or undesirable compatibility features. If a
dialect has changed in a way that impacts you significantly, report it
as described in Section 11.
7.3.3 ABI/Object Model changes
The object model and the name mangling scheme used by the C++ compiler
on I64 systems are different from those used on Alpha systems
(different from both /MODEL=ARM and /MODEL=ANSI). The I64 compiler uses
the interface described by the I64 Application Binary Interface (ABI).
See
http://www.codesourcery.com/cxx-abi/abi.html
for a draft description of the ABI specification.
The compiler has some additional encoding rules that are applied to
symbol names after the ABI name mangling is determined. All symbols
with C++ linkage have CRC encodings added to the name, are uppercased,
and shorten to 31 characters if necessary. Since the CRC is computed
before the name is uppercased, the symbol name is case sensitive even
though the final name is uppercase. /names=as_is and /names=upper are
not applicable to these symbols.
All symbols without C++ linkage will have CRC encodings added if they
are longer then 31 characters and /names=shorten is specified. Global
variables with C++ linkage are treated as if they have non-C++ linkage
for compatibility with C and older compilers.
7.3.4 Command-Line Qualifiers
This section describes qualifier differences for HP C++ on I64 systems.
Qualifiers/Features Not Supported on I64 Systems
The following command-line qualifiers and features are not supported on
C++ for I64 systems, and are diagnosed by default because ignoring them
is likely to alter program behavior:
- Comma lists are not supported. Their use provokes a fatal error.
- The /INSTRUCTION_SET=[NO]FLOATING_POINT qualifier is not available
on I64 systems.
- /L_DOUBLE_SIZE=64 is not available on I64 systems. If it is
specified, a warning message is issued, and /L_DOUBLE_SIZE=128 is used.
- /POINTER_SIZE=(LONG,64) is ignored.
Changed/Ignored Qualifiers
A number of other qualifiers not supported on I64 systems are, by
default, silently ignored by the compiler. These qualifiers fall into
two groups:
- Qualifiers that should not alter the behavior of a correct program
so, if ignored, should have no visible effect. Qualifiers that enable
optimizations typically have this characteristic.
- Qualifiers that might affect program behavior but, if ignored,
produce no significant change in the vast majority of programs.
Examples of qualifiers in this category are /NORTTI (the run-time
information is always generated) and /MODEL=ARM (the ANSI model is
functionally superior, and binary compatibility with existing object
code is not an issue for the OpenVMS I64 platform).
Two optional compiler messages can be enabled to diagnose most of these
cases:
- The QUALNA message diagnoses uses of the first group.
- The QUALCHANGE message diagnoses uses of the second group.
If you encounter porting problems, compile /WARN=ENABLE=QUALCHANGE to
determine if a qualifier change might be affecting your application.
If you wish to clean up your build scripts to remove extraneous
qualifiers that are not meaningful on I64 systems, you can enable the
QUALNA message.
A list of these qualifiers follows:
- /ARCHITECTURE=option
An additional keyword has been
added: ITANIUM2. If an Alpha keyword (EV4, EV5, EV56, PCA56, EV6,
EV68, EV7) is specified for option, it is ignored.
- /ASSUME
The following /ASSUME options are ignored on I64
systems and should not cause any behavior changes:
NORTTI_CTORVTBLS
NOPOINTERS_TO_GLOBALS
TRUSTED_SHORT_ALIGNMENT
WHOLE_PROGRAM
- /CHECK=UNINITIALIZED_VARIABLES
This qualifier has no effect in
this version of the compiler.
- /DISTINGUISH_NESTED_ENUMS
This qualifier only modified the
behavior of programs compiled with /MODEL=ARM. Since that model is not
supported on the I64 platform, this qualifier is meaningless.
- /EXCEPTIONS=NOCLEANUP
The NOCLEANUP keyword for the /EXCEPTIONS
qualifier is ignored.
- /EXCEPTIONS=IMPLICIT
The IMPLICIT keyword for the /EXCEPTIONS
qualifier is ignored.
- /FLOAT
The default for /FLOAT on OpenVMS I64 systems is
IEEE_FLOAT. See Section 7.3.5 for more information about
floating-point behavior on I64 systems.
- /IEEE_MODE
The default for /IEEE_MODE on I64 systems is
DENORM_RESULTS, which generates infinities, denorms, and NaNs without
exceptions. On OpenVMS Alpha systems, the default for /IEEE_MODE
when using /FLOAT=IEEE_FLOAT is FAST, which causes a FATAL error for
exceptional conditions such as divide-by-zero and overflow. See
Section 7.3.5 for more information.
- /MACHINE_CODE
The /MACHINE_CODE qualifier output will appear in
an .S file in the same directory as your listing file.
- The /MODEL=ARM qualifier is treated the same as the default
/MODEL=ANSI (except for the optional QUALCHANGE diagnostic).
- /OPTIMIZE
There are several changes to the /OPTIMIZE qualifier:
- On I64 systems, for /OPTIMIZE=INLINE, the keywords AUTOMATIC and
SPEED do the same thing.
Also, the ALL keyword does not necessarily
result in every possible call being inlined, as it does on Alpha
systems.
- The /OPTIMIZE=TUNE qualifier takes a new keyword: ITANIUM2, which
is the default at this time. If you specify an Alpha keyword, it is
ignored.
- The /OPTIMIZE=UNROLL=n qualifier on I64 systems does not
have the ability to control the specific number of times a loop is
unrolled. The only accepted values are /OPTIMIZE=UNROLL=1 which
disables loop unrolling, and /OPTIMIZE=UNROLL=0 which allows the
compiler's optimizer to decide how the loop should be unrolled. The
default is /OPTIMIZE=UNROLL=0.
- /OPTIMIZE=LIMIT_INLINE is ignored.
- /PREFIX_LIBRARY_ENTRIES
Note that
/PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES prefixes all functions defined by
the C99 standard including those that may not be supported in the
current run-time library. So calling functions introduced in C99 that
are not yet implemented in the OpenVMS C RTL will produce unresolved
references to symbols prefixed by DECC$ when the program is linked. The
compiler now issues a CC-W-NOTINCRTL message when it prefixes a name
that is not in the current C RTL.
- /TEMPLATE
See Section 7.3.9 for information on template
instantiation.
- /POINTER_SIZE=(SHORT,32) is ignored. Mixed pointer types are not
supported at this time.
- /SHOW=STATISTICS
The /SHOW=STATISTICS qualifier is ignored at
this time.
- /STANDARD=CFRONT
The /STANDARD=CFRONT qualifier is no longer
available. If it is specified, the compiler issues a warning message
and uses the default dialect, /STANDARD=ANSI.
New Qualifiers
The following command-line qualifier is new for C++ V7.1 for I64
systems:
- /[NO]PURE_CNAME
Affects insertion of the names into the global
namespace by
<cname>
headers. In /PURE_CNAME mode, the
<cname>
headers insert the names into the
std
namespace only, as defined by the C++ Standard, and the __PURE_CNAME
macro is predefined by the compiler. In /NOPURE_CNAME mode, the
<cname>
headers insert the name into the
std
namespace and also into the global namespace. The default depends
on the standard mode:
- In /STANDARD=STRICT_ANSI mode, the default is /PURE_CNAME.
- In all other standard modes, the default is /NOPURE_CNAME.
Inclusion of a
<name.h>
header instead of its
<cname.h>
counterpart (for example,
<stdio.h>
instead of
<cstdio>
) results in inserting names defined in the header into both the
std
namespace and the global namespace. Effectively, this is the same as
the inclusion of a
<cname>
header in the /NOPURE_CNAME mode. See Section 7.2.1 for more
information.
7.3.5 Floating Point
This section describes floating-point behavior on I64 systems.
IEEE Now the Default
On OpenVMS I64 systems, /FLOAT=IEEE_FLOAT is the default floating-point
representation. IEEE format data is assumed and IEEE floating-point
instructions are used. There is no hardware support for floating-point
representations other than IEEE, although you can specify the
/FLOAT=D_FLOAT or /FLOAT=G_FLOAT compiler option.
These VAX floating-point formats are supported in the I64 compiler by
generating run-time code that converts VAX floating-point formats to
IEEE format to perform arithmetic operations, and then converts the
IEEE result back to the appropriate VAX floating-point format. This
imposes additional run-time overhead and some loss of accuracy compared
to performing the operations in hardware on Alpha and VAX systems. The
software support for the VAX formats is provided to meet an important
functional compatibility requirement for certain applications that need
to deal with on-disk binary floating-point data.
On I64 systems, the default for /IEEE_MODE is DENORM_RESULTS, which is
a change from the default of /IEEE_MODE=FAST on Alpha systems. This
means that by default, floating-point operations may silently generate
values that print as Infinity or Nan (the industry-standard behavior),
instead of issuing a fatal run-time error as they would when using VAX
floating-point format or /IEEE_MODE=FAST. Also, the smallest-magnitude
nonzero value in this mode is much smaller because results are allowed
to enter the denormal range instead of being flushed to zero as soon as
the value is too small to represent with normalization.
The conversion between VAX floating-point formats and IEEE formats on
the Intel Itanium architecture is a transparent process that will not
impact most applications. All you need to do is recompile your
application. Because IEEE floating-point format is the default, unless
your build explicitly specifies VAX floating-point format options, a
simple rebuild for I64 systems will use the native IEEE formats
directly. For the large class of programs that do not directly depend
on the VAX formats for correct operation, this is the most desirable
way to build for I64 systems.
When you compile an OpenVMS application that specifies an option to use
VAX floating-point on an I64 system, the compiler automatically
generates code for converting floating-point formats. Whenever the
application performs a sequence of arithmetic operations, this code
does the following:
- Converts VAX floating-point formats to either IEEE single or IEEE
double floating-point formats.
- Performs arithmetic operations in IEEE floating-point arithmetic.
- Converts the resulting data from IEEE formats back to VAX formats.
Where no arithmetic operations are performed (VAX float fetches
followed by stores), no conversion will occur. The code handles such
situations as moves.
VAX floating-point formats have the same number of bits and precision
as their equivalent IEEE floating-point formats. For most applications,
the conversion process will be transparent and, therefore, a non-issue.
In a few cases, arithmetic calculations might have different results
because of the following differences between VAX and IEEE formats:
- Values of numbers represented
- Rounding rules
- Exception behavior
These differences might cause problems for applications that do any of
the following:
- Depend on exception behavior
- Measure the limits of floating-point behaviors
- Implement algorithms at maximal processor-specific accuracy
- Perform low-level emulations of other floating-point processors
- Use direct equality comparisons between floating-point values,
instead of appropriately ranged comparisons (a practice that is
extremely vulnerable to changes in compiler version or compiler
options, as well as architecture)
You can test an application's behavior with IEEE floating-point values
by first compiling it on an OpenVMS Alpha system using
/FLOAT=IEEE_FLOAT/IEEE_MODE=DENORM.
If that produces acceptable results, then simply build the application
on the OpenVMS I64 system using the same qualifier.
If you determine that simply recompiling with an /IEEE_MODE qualifier
is not sufficient because your application depends on the binary
representation of floating-point values, then first try building for
your I64 system by specifying the VAX floating-point option that was in
effect for your VAX or Alpha build. This causes the representation seen
by your code and on disk to remain unchanged, with some additional
runtime cost for the conversions generated by the compiler. If this is
not an efficient approach for your application, you can convert VAX
floating-point binary data in disk files to IEEE floating-point formats
before moving the application to an I64 system.
/IEEE_MODE Notes
On Alpha systems, the /IEEE_MODE qualifier generally has its greatest
effect on the generated code of a compilation. When calls are made
between functions compiled with different /IEEE_MODE qualifiers, each
function produces the /IEEE_MODE behavior with which it was compiled.
On I64 systems, the /IEEE_MODE qualifier primarily affects only the
setting of a hardware register at program startup. In general, the
/IEEE_MODE behavior for a given function is controlled by the
/IEEE_MODE option specified on the compilation that produced the main
program: the startup code for the main program sets the hardware
register according the command-line qualifiers used to compile the main
program.
When applied to a compilation that does not contain a main program, the
/IEEE_MODE qualifier does have some effect: it might affect the
evaluation of floating-point constant expressions, and it is used to
set the EXCEPTION_MODE used by the math library for calls from that
compilation. But the qualifier has no effect on the exceptional
behavior of floating-point calculations generated as inline code for
that compilation. Therefore, if floating-point exceptional behavior is
important to an application, all of its compilations, including the one
containing the main program, should be compiled with the same
/IEEE_MODE setting.
Even on Alpha systems, the particular setting of
/IEEE_MODE=UNDERFLOW_TO_ZERO has the following characteristic: its
primary effect requires the setting of a runtime status register, and
so it needs to be specified on the compilation containing the main
program in order to be effective in other compilations.
More Information
For more information on I64 floating-point behavior, see the white paper OpenVMS floating-point arithmetic on the Intel Itanium architecture at
http://www.hp.com/products1/evolution/alpha_retaintrust/download/i64-floating-pt-wp.pdf
.
7.3.6 Intrinsics and Builtins
The C++ built-in functions available on OpenVMS Alpha systems are also
available on I64 systems, with some differences, as described in this
section. This section also describes built-in functions that are
specific to I64 systems.
Builtin Differences on I64 Systems
The
<builtins.h>
header file contains comments noting which built-in functions are not
available or are not the preferred form for I64 systems. The compiler
issues diagnostics where using a different built-in function for I64
systems would be preferable.
Note
The comments in
<builtins.h>
reflect only what is explicitly present in that header file itself, and
in the compiler implementation. You should also consult the content and
comments in
<pal_builtins.h>
to determine more accurately what functionality is effectively provided
by including
<builtins.h>
. For example, if a program explicitly declares one of the Alpha
built-in functions and invokes it without having included
<builtins.h>
, the compiler might issue the BIFNOTAVAIL error message, regardless of
whether or not the function is available through a system service. If
the compilation does include
<builtins.h>
, and BIFNOTAVAIL is issued, then either there is no support at all for
the built-in function or a new version of
<pal_builtins.h>
is needed.
|
Here is a summary of these differences on I64 systems:
- There is no support for the
asm
,
fasm
, and
dasm
intrinsics (declared in the
<c_asm.h>
header file).
- The functionality provided by the special-case treatment of R26 in
an Alpha system
asm
, as in
asm("MOV R26,R0")
, is provided by a new built-in function for I64 systems:
__int64 __RETURN_ADDRESS(void);
|
This built-in function produces the address to which the function
containing the built-in call will return (the value of R26 on entry to
the function on Alpha systems; the value of B0 on entry to the function
on I64 systems). This built-in function cannot be used within a
function specified to use nonstandard linkage.
- The only PAL function calls implemented as built-in functions
within the compiler are the 24 queue-manipulation builtins. The queue
manipulation builtins generate calls to new OpenVMS system services
SYS$<name>, where <name> is the name of the builtin with
the leading underscores removed.
Any other OpenVMS PAL calls are
supported through macros defined in the
<pal_builtins.h>
header file included in the
<builtins.h>
header file. Typically, the macros in
<pal_builtins.h>
transform an invocation of an Alpha system builtin into a call to a
system service that performs the equivalent function on an I64 system.
Two notable exceptions are __PAL_GENTRAP and __PAL_BUGCHK, which
instead invoke the I64 specific compiler builtin __break2.
- There is no support for the various floating-point built-in
functions used by the OpenVMS math library (for example, operations
with chopped rounding and conversions).
- Most built-in functions that take a retry count are not supported.
This is necessary because the retry behavior allowed by Alpha
load-locked/store-conditional sequences does not exist on I64 systems.
There are two exceptions to this: __LOCK_LONG_RETRY and
__ACQUIRE_SEM_LONG_RETRY; in these cases, the retry behavior involves
comparisons of data values, not just load-locked/store-conditional.
- The __CMP_STORE_LONG and __CMP_STORE_QUAD built-in functions are
not supported. Use the new __CMP_SWAP form instead.
Built-in Functions Specific to I64 Systems
The
<builtins.h>
header file contains a section at the top conditionalized to just
__ia64 with the support for built-in functions specific to I64 systems.
This includes macro definitions for all of the registers that can be
specified to the __getReg, __setReg, __getIndReg, and __setIndReg
built-in functions. Parameters that are
const
-qualified require an argument that is a compile-time constant.
The following lists the C++ built-in functions available on OpenVMS I64
systems.
/* Intel compatible */
unsigned __int64 __getReg(const int __whichReg);
void __setReg(const int __whichReg, unsigned __int64 __value);
unsigned __int64 __getIndReg(const int __whichIndReg,
__int64 __index);
void __setIndReg(const int __whichIndReg, __int64 __index,
unsigned __int64 __value);
void __break(const int __break_arg); /* Native I64 arg */
void __dsrlz(void);
void __fc(__int64 __address);
void __fwb(void);
void __invalat(void);
void __invala(void); /* alternate spelling of __invalat */
void __isrlz(void);
void __itcd(__int64 __address);
void __itci(__int64 __address);
void __itrd(__int64 __whichTransReg, __int64 __address);
void __itri(__int64 __whichTransReg, __int64 __address);
void __ptce(__int64 __address);
void __ptcl(__int64 __address, __int64 __pagesz);
void __ptcg(__int64 __address, __int64 __pagesz);
void __ptcga(__int64 __address, __int64 __pagesz);
void __ptri(__int64 __address, __int64 __pagesz);
void __ptrd(__int64 __address, __int64 __pagesz);
void __rsm(const int __mask);
void __rum(const int __mask);
void __ssm(const int __mask);
void __sum(const int __mask);
void __synci(void);
__int64 /*address*/ __thash(__int64 __address);
__int64 /*address*/ __ttag(__int64 __address);
/* Intel _Interlocked intrinsics */
unsigned __int64 _InterlockedCompareExchange_acq(
unsigned int *__Destination,
unsigned __int64 __Newval,
unsigned __int64 __Comparand);
unsigned __int64 _InterlockedCompareExchange64_acq(
unsigned __int64 *__Destination,
unsigned __int64 __Newval,
unsigned __int64 __Comparand);
unsigned __int64 _InterlockedCompareExchange_rel(
unsigned int *__Destination,
unsigned __int64 __Newval,
unsigned __int64 __Comparand);
unsigned __int64 _InterlockedCompareExchange64_rel(
unsigned __int64 *__Destination | |