[llvm-commits] [dragonegg] r129278 - /dragonegg/trunk/Constants.cpp
Duncan Sands
baldrick at free.fr
Mon Apr 11 08:49:07 PDT 2011
Author: baldrick
Date: Mon Apr 11 10:49:07 2011
New Revision: 129278
URL: http://llvm.org/viewvc/llvm-project?rev=129278&view=rev
Log:
Rework handling of CONSTRUCTOR nodes with array type. The changes solve
two problems: (1) in Fortran it is possible for the value given for some
array element to be too small, in which case it needs to be padded to the
right size [see gcc testcase char_component_initializer_1.f90, modified to
have three array elements rather than two]; (2) if the user forced a small
alignment on the array, then a packed struct needs to be used in order to
not break the invariant that the converted value is not more aligned than
the GCC type.
Modified:
dragonegg/trunk/Constants.cpp
Modified: dragonegg/trunk/Constants.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/Constants.cpp?rev=129278&r1=129277&r2=129278&view=diff
==============================================================================
--- dragonegg/trunk/Constants.cpp (original)
+++ dragonegg/trunk/Constants.cpp Mon Apr 11 10:49:07 2011
@@ -606,133 +606,148 @@
return AddressOf(TREE_OPERAND(exp, 0));
}
+/// ConvertArrayCONSTRUCTOR - Convert a CONSTRUCTOR with array or vector type.
static Constant *ConvertArrayCONSTRUCTOR(tree exp) {
- // Vectors are like arrays, but the domain is stored via an array
- // type indirectly.
+ const TargetData &TD = getTargetData();
- // If we have a lower bound for the range of the type, get it.
tree init_type = TREE_TYPE(exp);
+ const Type *InitTy = ConvertType(init_type);
+
tree elt_type = TREE_TYPE(init_type);
+ const Type *EltTy = ConvertType(elt_type);
- tree min_element = size_zero_node;
- std::vector<Constant*> ResultElts;
+ // Check that the element type has a known, constant size.
+ assert(isSequentialCompatible(init_type) && "Variable sized array element!");
+ uint64_t EltSize = TD.getTypeAllocSizeInBits(EltTy);
- if (TREE_CODE(init_type) == VECTOR_TYPE) {
- ResultElts.resize(TYPE_VECTOR_SUBPARTS(init_type));
- } else {
- assert(TREE_CODE(init_type) == ARRAY_TYPE && "Unknown type for init");
- tree Domain = TYPE_DOMAIN(init_type);
- if (Domain && TYPE_MIN_VALUE(Domain))
- min_element = fold_convert(sizetype, TYPE_MIN_VALUE(Domain));
-
- if (Domain && TYPE_MAX_VALUE(Domain)) {
- tree max_element = fold_convert(sizetype, TYPE_MAX_VALUE(Domain));
- tree size = size_binop (MINUS_EXPR, max_element, min_element);
- size = size_binop (PLUS_EXPR, size, size_one_node);
+ /// Elts - The initial values to use for the array elements. A null entry
+ /// means that the corresponding array element should be default initialized.
+ std::vector<Constant*> Elts;
- if (host_integerp(size, 1))
- ResultElts.resize(tree_low_cst(size, 1));
- }
- }
+ // Resize to the number of array elements if known. This ensures that every
+ // element will be at least default initialized even if no initial value is
+ // given for it.
+ uint64_t TypeElts = TREE_CODE(init_type) == ARRAY_TYPE ?
+ ArrayLengthOf(init_type) : TYPE_VECTOR_SUBPARTS(init_type);
+ if (TypeElts != ~0ULL)
+ Elts.resize(TypeElts);
+
+ // If GCC indices into the array need adjusting to make them zero indexed then
+ // record here the value to subtract off.
+ tree lower_bnd = NULL_TREE;
+ if (TREE_CODE(init_type) == ARRAY_TYPE && TYPE_DOMAIN(init_type) &&
+ !integer_zerop(TYPE_MIN_VALUE(TYPE_DOMAIN(init_type))))
+ lower_bnd = TYPE_MIN_VALUE(TYPE_DOMAIN(init_type));
- unsigned NextFieldToFill = 0;
+ unsigned NextIndex = 0;
unsigned HOST_WIDE_INT ix;
tree elt_index, elt_value;
- Constant *SomeVal = 0;
- FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), ix, elt_index, elt_value) {
+ FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(exp), ix, elt_index, elt_value) {
// Find and decode the constructor's value.
Constant *Val = ConvertInitializerWithCast(elt_value, elt_type);
- SomeVal = Val;
+ uint64_t ValSize = TD.getTypeAllocSizeInBits(Val->getType());
+ assert(ValSize <= EltSize && "Element initial value too big!");
+
+ // If the initial value is smaller than the element size then pad it out.
+ if (ValSize < EltSize) {
+ unsigned PadBits = EltSize - ValSize;
+ assert(PadBits % BITS_PER_UNIT == 0 && "Non-unit type size?");
+ unsigned Units = PadBits / BITS_PER_UNIT;
+ Constant *Padding = UndefValue::get(GetUnitType(Context, Units));
+ Val = ConstantStruct::get(Context, false, Val, Padding, NULL);
+ }
// Get the index position of the element within the array. Note that this
// can be NULL_TREE, which means that it belongs in the next available slot.
tree index = elt_index;
- // The first and last field to fill in, inclusive.
- unsigned FieldOffset, FieldLastOffset;
- if (index && TREE_CODE(index) == RANGE_EXPR) {
- tree first = fold_convert (sizetype, TREE_OPERAND(index, 0));
- tree last = fold_convert (sizetype, TREE_OPERAND(index, 1));
-
- first = size_binop (MINUS_EXPR, first, min_element);
- last = size_binop (MINUS_EXPR, last, min_element);
+ // The first and last elements to fill in, inclusive.
+ unsigned FirstIndex, LastIndex;
+ if (!index) {
+ LastIndex = FirstIndex = NextIndex;
+ } else if (TREE_CODE(index) == RANGE_EXPR) {
+ tree first = TREE_OPERAND(index, 0);
+ tree last = TREE_OPERAND(index, 1);
+
+ // Subtract off the lower bound if any to ensure indices start from zero.
+ if (lower_bnd != NULL_TREE) {
+ first = fold_build2(MINUS_EXPR, TREE_TYPE(first), first, lower_bnd);
+ last = fold_build2(MINUS_EXPR, TREE_TYPE(last), last, lower_bnd);
+ }
assert(host_integerp(first, 1) && host_integerp(last, 1) &&
"Unknown range_expr!");
- FieldOffset = tree_low_cst(first, 1);
- FieldLastOffset = tree_low_cst(last, 1);
- } else if (index) {
- index = size_binop (MINUS_EXPR, fold_convert (sizetype, index),
- min_element);
- assert(host_integerp(index, 1));
- FieldOffset = tree_low_cst(index, 1);
- FieldLastOffset = FieldOffset;
+ FirstIndex = tree_low_cst(first, 1);
+ LastIndex = tree_low_cst(last, 1);
} else {
- FieldOffset = NextFieldToFill;
- FieldLastOffset = FieldOffset;
+ // Subtract off the lower bound if any to ensure indices start from zero.
+ if (lower_bnd != NULL_TREE)
+ index = fold_build2(MINUS_EXPR, TREE_TYPE(index), index, lower_bnd);
+ assert(host_integerp(index, 1));
+ FirstIndex = tree_low_cst(index, 1);
+ LastIndex = FirstIndex;
}
// Process all of the elements in the range.
- for (--FieldOffset; FieldOffset != FieldLastOffset; ) {
- ++FieldOffset;
- if (FieldOffset == ResultElts.size())
- ResultElts.push_back(Val);
- else {
- if (FieldOffset >= ResultElts.size())
- ResultElts.resize(FieldOffset+1);
- ResultElts[FieldOffset] = Val;
- }
+ if (LastIndex >= Elts.size())
+ Elts.resize(LastIndex + 1);
+ for (; FirstIndex <= LastIndex; ++FirstIndex)
+ Elts[FirstIndex] = Val;
- NextFieldToFill = FieldOffset+1;
- }
+ NextIndex = FirstIndex;
}
+ unsigned NumElts = Elts.size();
+
// Zero length array.
- if (ResultElts.empty())
- return getDefaultValue(ConvertType(TREE_TYPE(exp)));
- assert(SomeVal && "If we had some initializer, we should have some value!");
+ if (!NumElts)
+ return getDefaultValue(InitTy);
+
+ // Default initialize any elements that had no initial value specified.
+ Constant *DefaultElt = getDefaultValue(EltTy);
+ for (unsigned i = 0; i != NumElts; ++i)
+ if (!Elts[i])
+ Elts[i] = DefaultElt;
+
+ // Check whether any of the elements have different types. If so we need to
+ // return a struct instead of an array. This can occur in cases where we have
+ // an array of unions, and the various unions had different parts initialized.
+ // While there, compute the maximum element alignment.
+ bool UseStruct = false;
+ const Type *ActualEltTy = Elts[0]->getType();
+ unsigned MaxAlign = TD.getABITypeAlignment(ActualEltTy);
+ for (unsigned i = 1; i != NumElts; ++i)
+ if (Elts[i]->getType() != ActualEltTy) {
+ MaxAlign = std::max(TD.getABITypeAlignment(Elts[i]->getType()), MaxAlign);
+ UseStruct = true;
+ }
+
+ // If any elements are more aligned than the GCC type then we need to return a
+ // packed struct. This can happen if the user forced a small alignment on the
+ // array type.
+ bool Pack = MaxAlign * 8 > TYPE_ALIGN(TREE_TYPE(exp));
- // Do a post-pass over all of the elements. We're taking care of two things
- // here:
- // #1. If any elements did not have initializers specified, provide them
- // with a null init.
- // #2. If any of the elements have different types, return a struct instead
- // of an array. This can occur in cases where we have an array of
- // unions, and the various unions had different pieces init'd.
- const Type *ElTy = SomeVal->getType();
- Constant *Filler = Constant::getNullValue(ElTy);
- bool AllEltsSameType = true;
- for (unsigned i = 0, e = ResultElts.size(); i != e; ++i) {
- if (ResultElts[i] == 0)
- ResultElts[i] = Filler;
- else if (ResultElts[i]->getType() != ElTy)
- AllEltsSameType = false;
- }
-
- if (TREE_CODE(init_type) == VECTOR_TYPE) {
- assert(AllEltsSameType && "Vector of heterogeneous element types?");
- return ConstantVector::get(ResultElts);
- }
-
- Constant *Res = AllEltsSameType ?
- ConstantArray::get(ArrayType::get(ElTy, ResultElts.size()), ResultElts) :
- ConstantStruct::get(Context, ResultElts, false);
-
- // If the array does not require extra padding, return it.
- const Type *InitType = ConvertType(init_type);
- uint64_t ExpectedBits = getTargetData().getTypeAllocSizeInBits(InitType);
- uint64_t FoundBits = getTargetData().getTypeAllocSizeInBits(Res->getType());
- // The initializer may be bigger than the type if init_type is variable sized
- // or has no size (in which case the size is determined by the initial value).
- if (ExpectedBits <= FoundBits)
- return Res;
-
- // Wrap the array in a struct with padding at the end.
- Constant *PadElts[2];
- PadElts[0] = Res;
- PadElts[1] = UndefValue::get(ArrayType::get(Type::getInt8Ty(Context),
- (ExpectedBits - FoundBits) / 8));
- return ConstantStruct::get(Context, PadElts, 2, false);
+ // We guarantee that initializers are always at least as big as the LLVM type
+ // for the initializer. If needed, append padding to ensure this.
+ uint64_t TypeSize = TD.getTypeAllocSizeInBits(InitTy);
+ if (NumElts * EltSize < TypeSize) {
+ unsigned PadBits = TypeSize - NumElts * EltSize;
+ assert(PadBits % BITS_PER_UNIT == 0 && "Non-unit type size?");
+ unsigned Units = PadBits / BITS_PER_UNIT;
+ Elts.push_back(UndefValue::get(GetUnitType(Context, Units)));
+ UseStruct = true;
+ }
+
+ // Return as a struct if the contents are not homogeneous.
+ if (UseStruct || Pack)
+ return ConstantStruct::get(Context, Elts, Pack);
+
+ // Make the IR more pleasant by returning as a vector if the GCC type was a
+ // vector. However this is only correct if the initial values had the same
+ // type as the vector element type, rather than some random other type.
+ return ActualEltTy == EltTy && TREE_CODE(init_type) == VECTOR_TYPE ?
+ ConstantVector::get(Elts) :
+ ConstantArray::get(ArrayType::get(ActualEltTy, Elts.size()), Elts);
}
/// FieldContents - A constant restricted to a range of bits. Any part of the
@@ -903,10 +918,10 @@
// For each field for which an initial value was specified, set the bits
// occupied by the field to that value.
- unsigned HOST_WIDE_INT idx;
+ unsigned HOST_WIDE_INT ix;
tree field, next_field, value;
next_field = TYPE_FIELDS(TREE_TYPE(exp));
- FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(exp), idx, field, value) {
+ FOR_EACH_CONSTRUCTOR_ELT(CONSTRUCTOR_ELTS(exp), ix, field, value) {
if (!field) {
// Move on to the next FIELD_DECL, skipping contained methods, types etc.
field = next_field;
@@ -1009,9 +1024,9 @@
}
static Constant *ConvertCONSTRUCTOR(tree exp) {
- // If the constructor is empty then default initialize all components. It is
- // safe to use the LLVM type here as it covers every part of the GCC type that
- // can be default initialized.
+ // If the constructor is empty then default initialize all of the components.
+ // It is safe to use the LLVM type here as it covers every part of the GCC
+ // type that can possibly be default initialized.
if (CONSTRUCTOR_NELTS(exp) == 0)
return getDefaultValue(ConvertType(TREE_TYPE(exp)));
More information about the llvm-commits
mailing list