1

Consider the following code :

My_Constant : constant := 2;

Is "My_Constant" a variable or a C language macro-like, so does it have a storage in memory ?

backlash
  • 777
  • 1
  • 6
  • 12

2 Answers2

7

Note that constant just means that you cannot modify the object. It doesn't necessarily mean that the value of the constant is known at compile time. So there are three cases to consider:

(1) A constant with a type, whose value is known at compile time:

My_Constant : constant Integer := 3;

In this case, there's no reason for the compiler to allocate memory for the constant; it can use the value 3 whenever it sees My_Constant (and is likely to use 3 as the immediate operand of instructions, where possible; if it sees something like My_Constant * 2 then it can use the value 6 as an immediate operand). The compiler is allowed to allocate memory for the constant, but I don't think any decent compiler would do so, in a simple case like this with a small number. If it were a really large number that wouldn't fit into an immediate operand, it might make more sense to allocate space for the number somewhere (if it can do so in a way that saves on code space).

In a more complex case:

My_Record_Constant : constant Rec := (Field_1 => 100, Field_2 => 201, Field_3 => 44);

Here, a good compiler can decide whether or not to store the constant in memory based on how it's used. If the only uses are accesses of individual fields (My_Record_Constant.Field_1), the compiler could replace those with the integer values, as if they were integer constants, and there would be no need to store the entire record in memory.

However, using aliased will cause any constant to be forced into memory:

My_Constant : aliased constant Integer := 3;

Now memory has to be allocated because the program could say My_Constant'Access (the access type has to be access constant Integer).

(2) A constant whose value is not known at compile time:

My_Constant : constant Integer := Some_Function_Call (Parameter_1);

The function is called once, when the integer's declaration is elaborated. Since it is not a macro expansion, uses of My_Constant do not generate calls to the function. Example:

procedure Some_Procedure is
    My_Constant : constant Integer := Some_Function_Call (Parameter_1);
begin
    Put_Line (Integer'Image (My_Constant));
    Put_Line (Integer'Image (My_Constant));
end Some_Procedure;

Some_Function_Call is called each time Some_Procedure is called, but it is called once, not two or three times.

Most likely, this requires the value to be stored in memory to hold the function result, so space will be allocated for My_Constant. (This still isn't a requirement. If a good optimizing compiler can somehow figure out that Some_Function_Call will return a known value, it can use that information.)

(3) A named number. This is the example you have, where there is no type:

My_Constant : constant := 2;

The language rules say the value must be known at compile time. This is the equivalent of using that number every time My_Constant is seen, so it's the closest thing to a C macro you're going to get in Ada. But the effect is basically the same as in (1) [except with fewer restrictions on type compatibility]. The compiler probably will not allocate space for it, but it might do so for a larger value. Note that this syntax is allowed only for numeric values (integer or real).

ajb
  • 31,309
  • 3
  • 58
  • 84
  • 1
    Note that I would argue that the `aliased` keyword can be optimized out if the compiler can find out that the `'Access` is never used on that variable. Even if the documentation says that the production is expected to create space in memory for that variable. – Alexis Wilke Sep 14 '14 at 20:16
  • @AlexisWilke Well, there are other attributes that would need to be checked for, such as `'Address`, but overall I think you're right. I believe the RM is rather loose on such matters; it specifies the semantics but pretty much lets compilers generate any code that behaves according to the semantics. – ajb Sep 15 '14 at 01:03
0

Another variation on option (1) above is for a constant array.

primes : constant array(integer range <>) of integer := (1, 3, 5, 7, 11, 13, 17, 19, 23);

If the compiler can see it being accessed by an index, it will have to store the array. I doubt the compiler writers would try and special case any other obscure corner condition to save some memory - they have enough other special corner cases to worry about in Ada!

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
Dale Stanbrough
  • 423
  • 3
  • 11
  • Ummm... you do mean to include an actual type name in the above declaration, right? What you've typed in won't compile. – ajb Aug 02 '14 at 16:23
  • FYI, you're wrong about what compilers try to do, if I'm understanding you correctly. I believe Irvine Compiler's Ada compiler does store the array values, and if the array is accessed by an index that is _known at compile time_, the compiler will substitute the element value rather than generating an array reference. If the result is that the symbol representing the array's memory storage is never referenced, the entire storage may be optimized away. – ajb Aug 02 '14 at 16:26
  • I really don't see why a statement like `primes(3)` would not be optimized as `5`. Compilers are smart enough to do such things at compile time. And if all accesses are that way, then array itself does not need to be saved anywhere since all references will disappear. – Alexis Wilke Sep 14 '14 at 20:19