This isn't really a complete implementation of VLA codegen, but it's a
start. This patch implements all of the basics for VLAs, including
sizeof and multidimensional VLAs.
There are a still some things that aren't really correct. One is that
I've taken a few shortcuts assuming that everything is an i32.
Another is that this doesn't handle typedefs and casts correctly,
because it isn't forcing the size to be emitted in the right place.
The patch could some of refactoring, and I've only tested it very
lightly.
On the bright side, it can handle declaring and indexing into a
44-dimensional vla while only emitting 86 multiplies, as opposed to
gcc's 946 :-)
Does the approach in this patch look reasonable?
-Eli
Index: CodeGen/CodeGenFunction.cpp
===================================================================
--- CodeGen/CodeGenFunction.cpp (revision 47175)
+++ CodeGen/CodeGenFunction.cpp (working copy)
@@ -42,6 +42,7 @@
const llvm::Type *CodeGenFunction::ConvertType(QualType T) {
+ EmitType(T);
return CGM.getTypes().ConvertType(T);
}
Index: CodeGen/CGExprScalar.cpp
===================================================================
--- CodeGen/CGExprScalar.cpp (revision 47175)
+++ CodeGen/CGExprScalar.cpp (working copy)
@@ -473,15 +473,15 @@
// will not true when we add support for VLAs.
Value *V = EmitLValue(Op).getAddress(); // Bitfields can't be arrays.
- assert(isa<llvm::PointerType>(V->getType()) &&
- isa<llvm::ArrayType>(cast<llvm::PointerType>(V->getType())
- ->getElementType()) &&
- "Doesn't support VLAs yet!");
- llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
-
- llvm::Value *Ops[] = {Idx0, Idx0};
- V = Builder.CreateGEP(V, Ops, Ops+2, "arraydecay");
-
+ if (!Op->getType()->isVariablyModifiedType()) {
+ // Note that we don't have to do anything here for variable
+ // array types; the LLVM type is already correct.
+ llvm::Constant *Idx0 = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0);
+
+ llvm::Value *Ops[] = {Idx0, Idx0};
+ V = Builder.CreateGEP(V, Ops, Ops+2, "arraydecay");
+ }
+
// The resultant pointer type can be implicitly casted to other pointer
// types as well, for example void*.
const llvm::Type *DestPTy = ConvertType(E->getType());
@@ -599,6 +599,14 @@
/// an integer (RetType).
Value *ScalarExprEmitter::EmitSizeAlignOf(QualType TypeToSize,
QualType RetType,bool isSizeOf){
+ if (isSizeOf && !TypeToSize->isConstantSizeType()) {
+ llvm::Value* Size = CGF.EmitType(TypeToSize);
+ QualType BaseType = TypeToSize->getAsVariableArrayType()->getBaseType();
+ uint64_t baseSize = CGF.getContext().getTypeSize(BaseType,
SourceLocation());
+ Size = Builder.CreateMul(Size, llvm::ConstantInt::get(llvm::Type::Int32Ty,
baseSize/8));
+ return Size;
+ }
+
/// FIXME: This doesn't handle VLAs yet!
std::pair<uint64_t, unsigned> Info =
CGF.getContext().getTypeInfo(TypeToSize, SourceLocation());
Index: CodeGen/CodeGenFunction.h
===================================================================
--- CodeGen/CodeGenFunction.h (revision 47175)
+++ CodeGen/CodeGenFunction.h (working copy)
@@ -261,6 +261,9 @@
/// LabelMap - This keeps track of the LLVM basic block for each C label.
llvm::DenseMap<const LabelStmt*, llvm::BasicBlock*> LabelMap;
+
+ // VLASizeMap - This keeps track of the associated size for each VLA type
+ llvm::DenseMap<const Expr*, llvm::Value*> VLASizeMap;
// BreakContinueStack - This keeps track of where break and continue
// statements should jump to.
@@ -476,6 +479,10 @@
bool DestIsVolatile);
/// LoadComplexFromAddr - Load a complex number from the specified address.
ComplexPairTy LoadComplexFromAddr(llvm::Value *SrcAddr, bool SrcIsVolatile);
+
+ // Emit a type; this causes the sizes of variably modified types to be
+ // calculated in places like declarations and typedefs.
+ llvm::Value* EmitType(QualType Ty);
};
} // end namespace CodeGen
} // end namespace clang
Index: CodeGen/CGDecl.cpp
===================================================================
--- CodeGen/CGDecl.cpp (revision 47175)
+++ CodeGen/CGDecl.cpp (working copy)
@@ -34,6 +34,7 @@
case Decl::Class: // class X;
case Decl::Enum: // enum X;
// None of these decls require codegen support.
+ // FIXME: Except typedefs containing a VLA type!
return;
case Decl::BlockVar:
@@ -95,7 +96,34 @@
Ty.getAddressSpace());
}
-
+
+llvm::Value* CodeGenFunction::EmitType(QualType Ty) {
+ if (const PointerType* PT = Ty->getAsPointerType()) {
+ EmitType(PT->getPointeeType());
+ } else if (const VariableArrayType* VAT = Ty->getAsVariableArrayType()) {
+ if (llvm::Value* SizeLocation = VLASizeMap[VAT->getSizeExpr()]) {
+ return Builder.CreateLoad(SizeLocation);
+ } else {
+ // FIXME: We need to sext (or zext?) smaller stuff
+ // FIXME: What to do about larger stuff? We can't alloca more than i32;
+ // also, we cause an implicit buffer overflow for large allocations!
+ llvm::Value* CurSize = EmitScalarExpr(VAT->getSizeExpr());
+ if (llvm::Value* SubArraySize = EmitType(VAT->getElementType())) {
+ // We multiply here to figure out the total size; all the places
+ // that need this info want the total size anyway, and this
+ // prevents quadratic behavior for many-dimensional arrays.
+ CurSize = Builder.CreateMul(SubArraySize, CurSize);
+ }
+ llvm::Value *SizeLocation = CreateTempAlloca(llvm::Type::Int32Ty,
+ ".size");
+ Builder.CreateStore(CurSize, SizeLocation, false);
+ VLASizeMap[VAT->getSizeExpr()] = SizeLocation;
+ return CurSize;
+ }
+ }
+ return 0;
+}
+
/// EmitLocalBlockVarDecl - Emit code and set up an entry in LocalDeclMap for a
/// variable declaration with auto, register, or no storage class specifier.
/// These turn into simple stack objects.
@@ -109,8 +137,11 @@
// TODO: Alignment
DeclPtr = CreateTempAlloca(LTy, D.getName());
} else {
- // TODO: Create a dynamic alloca.
- assert(0 && "FIXME: Local VLAs not implemented yet");
+ const llvm::Type *LTy = ConvertType(Ty);
+ const VariableArrayType* VAT = Ty->getAsVariableArrayType();
+ assert(VAT && "Non-constant size type must be VAT here!");
+ llvm::Value *Size = Builder.CreateLoad(VLASizeMap[VAT->getSizeExpr()]);
+ DeclPtr = Builder.CreateAlloca(LTy, Size, D.getName());
}
llvm::Value *&DMEntry = LocalDeclMap[&D];
Index: CodeGen/CGExpr.cpp
===================================================================
--- CodeGen/CGExpr.cpp (revision 47175)
+++ CodeGen/CGExpr.cpp (working copy)
@@ -438,8 +438,9 @@
// We know that the pointer points to a type of the correct size, unless the
// size is a VLA.
- if (!E->getType()->isConstantSizeType())
- assert(0 && "VLA idx not implemented");
+ if (!E->getType()->isConstantSizeType()) {
+ Idx = Builder.CreateMul(Idx,
Builder.CreateLoad(VLASizeMap[E->getType()->getAsVariableArrayType()->getSizeExpr()]));
+ }
return LValue::MakeAddr(Builder.CreateGEP(Base, Idx, "arrayidx"));
}
_______________________________________________
cfe-dev mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev