@@ -43,10 +43,6 @@ static llvm::ConstantInt *getMetadataKind(IRGenModule &IGM,
4343 return llvm::ConstantInt::get (IGM.MetadataKindTy , uint8_t (kind));
4444}
4545
46- static llvm::ConstantInt *getSize (IRGenFunction &IGF, Size value) {
47- return llvm::ConstantInt::get (IGF.IGM .SizeTy , value.getValue ());
48- }
49-
5046static llvm::ConstantInt *getSize (IRGenFunction &IGF,
5147 const llvm::APInt &value) {
5248 return cast<llvm::ConstantInt>(llvm::ConstantInt::get (IGF.IGM .SizeTy , value));
@@ -169,35 +165,69 @@ static void bindNecessaryBindings(IRGenFunction &IGF,
169165 bindings.restore (IGF, bindingsBuffer);
170166}
171167
172- // / Lay out an array on the heap.
173- ArrayHeapLayout::ArrayHeapLayout (IRGenFunction &IGF, CanType T)
174- : ElementTI(IGF.getFragileTypeInfo(T)), Bindings(IGF.IGM, T) {
168+ // / Compute the basic information for how to lay out a heap array .
169+ HeapArrayInfo::HeapArrayInfo (IRGenFunction &IGF, CanType T)
170+ : ElementTI(IGF.getFragileTypeInfo(T)), Bindings(IGF.IGM, T) {}
175171
176- // Add the heap header.
177- Size size (0 );
178- Alignment align (1 );
172+ // / Lay out the allocation in this IGF.
173+ HeapArrayInfo::Layout HeapArrayInfo::getLayout (IRGenFunction &IGF) const {
174+ // Start with the heap header.
175+ Size headerSize (0 );
176+ Alignment headerAlign (1 );
179177 SmallVector<llvm::Type*, 4 > fields;
180- addHeapHeaderToLayout (IGF.IGM , size, align , fields);
181- assert ((size % align ).isZero ());
182- assert (align >= IGF.IGM .getPointerAlignment ());
178+ addHeapHeaderToLayout (IGF.IGM , headerSize, headerAlign , fields);
179+ assert ((headerSize % headerAlign ).isZero ());
180+ assert (headerAlign >= IGF.IGM .getPointerAlignment ());
183181
184182 // Add the length field.
185- size += IGF.IGM .getPointerSize ();
186- assert (size == getArrayHeapHeaderSize (IGF.IGM ));
183+ headerSize += IGF.IGM .getPointerSize ();
184+ assert (headerSize == getArrayHeapHeaderSize (IGF.IGM ));
187185
188186 // Add the necessary bindings size.
189- size += Bindings.getBufferSize (IGF.IGM );
187+ headerSize += Bindings.getBufferSize (IGF.IGM );
188+
189+ // The easy case is when we know the layout of the element.
190+ if (auto fixedElementTI = dyn_cast<FixedTypeInfo>(&ElementTI)) {
191+ // Update the required alignment.
192+ if (fixedElementTI->getFixedAlignment () > headerAlign)
193+ headerAlign = fixedElementTI->getFixedAlignment ();
194+
195+ // Round the size up to the alignment of the element type.
196+ // FIXME: resilient types.
197+ headerSize = headerSize.roundUpToAlignment (
198+ fixedElementTI->getFixedAlignment ());
199+
200+ return {
201+ IGF.IGM .getSize (headerSize),
202+ IGF.IGM .getSize (headerAlign.asSize ()),
203+ headerAlign
204+ };
205+ }
206+
207+ // Otherwise, we need to do this computation at runtime.
208+
209+ // Read the alignment of the element type.
210+ llvm::Value *eltAlign = ElementTI.getAlignment (IGF);
211+
212+ // Round the header size up to the element alignment.
213+ llvm::Value *headerSizeV = IGF.IGM .getSize (headerSize);
190214
191- // Update the required alignment.
192- if (ElementTI.getFixedAlignment () > align)
193- align = ElementTI.getFixedAlignment ();
215+ // mask = alignment - 1
216+ // headerSize = (headerSize + mask) & ~mask
217+ auto eltAlignMask = IGF.Builder .CreateSub (eltAlign, IGF.IGM .getSize (Size (1 )));
218+ headerSizeV = IGF.Builder .CreateAdd (headerSizeV, eltAlignMask);
219+ llvm::Value *eltAlignMaskInverted = IGF.Builder .CreateNot (eltAlignMask);
220+ headerSizeV = IGF.Builder .CreateAnd (headerSizeV, eltAlignMaskInverted,
221+ " array-header-size" );
194222
195- // Round the size up to the alignment of the element type.
196- // FIXME: resilient types.
197- size = size.roundUpToAlignment (ElementTI.getFixedAlignment ());
223+ // allocAlign = max(headerAlign, alignment)
224+ llvm::Value *headerAlignV = IGF.IGM .getSize (headerAlign.asSize ());
225+ llvm::Value *overaligned =
226+ IGF.Builder .CreateICmpUGT (eltAlign, headerAlignV, " overaligned" );
227+ llvm::Value *allocAlign =
228+ IGF.Builder .CreateSelect (overaligned, eltAlign, headerAlignV);
198229
199- HeaderSize = size;
200- Align = align;
230+ return { headerSizeV, allocAlign, headerAlign };
201231}
202232
203233// / Destroy all the elements of an array.
@@ -252,7 +282,7 @@ static void emitArrayDestroy(IRGenFunction &IGF,
252282// / TODO: give this some reasonable name and possibly linkage.
253283static llvm::Constant *
254284createArrayDtorFn (IRGenModule &IGM,
255- const ArrayHeapLayout &layout ,
285+ const HeapArrayInfo &arrayInfo ,
256286 const NecessaryBindings &bindings) {
257287 llvm::Function *fn =
258288 llvm::Function::Create (IGM.DeallocatingDtorTy ,
@@ -262,20 +292,26 @@ createArrayDtorFn(IRGenModule &IGM,
262292 IRGenFunction IGF (IGM, CanType (), llvm::ArrayRef<Pattern*>(),
263293 ExplosionKind::Minimal, 0 , fn, Prologue::Bare);
264294
295+ // Bind the necessary archetypes. This is required before we can
296+ // lay out the array in this IGF.
265297 llvm::Value *header = fn->arg_begin ();
266- Address lengthPtr = layout.getLengthPointer (IGF, header);
298+ bindNecessaryBindings (IGF, bindings,
299+ Address (header, IGM.getPointerAlignment ()));
300+
301+ auto layout = arrayInfo.getLayout (IGF);
302+
303+ Address lengthPtr = arrayInfo.getLengthPointer (IGF, layout, header);
267304 llvm::Value *length = IGF.Builder .CreateLoad (lengthPtr, " length" );
268305
269- // Bind the necessary archetypes.
270- bindNecessaryBindings (IGF, bindings, Address (header, layout.getAlignment ()));
306+ auto &eltTI = arrayInfo.getElementTypeInfo ();
271307
272308 // If the layout isn't known to be POD, we actually have to do work here.
273- if (!layout. getElementTypeInfo () .isPOD (ResilienceScope::Local)) {
274- llvm::Value *elementSize = layout. getElementTypeInfo () .getStride (IGF);
309+ if (!eltTI .isPOD (ResilienceScope::Local)) {
310+ llvm::Value *elementSize = eltTI .getStride (IGF);
275311
276- llvm::Value *begin = layout .getBeginPointer (IGF, header);
312+ llvm::Value *begin = arrayInfo .getBeginPointer (IGF, layout , header);
277313 llvm::Value *end;
278- if (layout. getElementTypeInfo (). StorageType -> isSized ( )) {
314+ if (isa<FixedTypeInfo>(eltTI )) {
279315 end = IGF.Builder .CreateInBoundsGEP (begin, length, " end" );
280316 } else {
281317 end = IGF.Builder .CreateBitCast (begin, IGF.IGM .Int8PtrTy );
@@ -284,16 +320,17 @@ createArrayDtorFn(IRGenModule &IGM,
284320 end = IGF.Builder .CreateBitCast (end, begin->getType ());
285321 }
286322
287- emitArrayDestroy (IGF, begin, end, layout. getElementTypeInfo () , elementSize);
323+ emitArrayDestroy (IGF, begin, end, eltTI , elementSize);
288324 }
289325
290- llvm::Value *size = layout.getAllocationSize (IGF, length, false , false );
326+ llvm::Value *size =
327+ arrayInfo.getAllocationSize (IGF, layout, length, false , false );
291328 IGF.Builder .CreateRet (size);
292329
293330 return fn;
294331}
295332
296- llvm::Constant *ArrayHeapLayout ::getPrivateMetadata (IRGenModule &IGM) const {
333+ llvm::Constant *HeapArrayInfo ::getPrivateMetadata (IRGenModule &IGM) const {
297334 return buildPrivateMetadata (IGM, createArrayDtorFn (IGM, *this , Bindings),
298335 MetadataKind::HeapArray);
299336}
@@ -327,15 +364,17 @@ static llvm::Value *checkOverflow(IRGenFunction &IGF,
327364// / this is false for computations involving a known-good length
328365// / \param updateLength - whether to update the 'length' parameter
329366// / with the proper length, i.e. the length as a size_t
330- llvm::Value *ArrayHeapLayout::getAllocationSize (IRGenFunction &IGF,
331- llvm::Value *&length,
332- bool canOverflow,
333- bool updateLength) const {
367+ llvm::Value *HeapArrayInfo::getAllocationSize (IRGenFunction &IGF,
368+ const Layout &layout,
369+ llvm::Value *&length,
370+ bool canOverflow,
371+ bool updateLength) const {
334372 // We're computing HeaderSize + length * sizeof(element).
335373
336374 // Easy case: the length is a static constant.
337375 llvm::ConstantInt *clength = dyn_cast<llvm::ConstantInt>(length);
338- if (clength && ElementTI.StorageType ->isSized ()) {
376+ if (clength && ElementTI.isFixedSize ()) {
377+ auto &fixedElementTI = cast<FixedTypeInfo>(ElementTI);
339378 unsigned sizeWidth = IGF.IGM .SizeTy ->getBitWidth ();
340379
341380 // Get the length to size_t, making sure it isn't too large.
@@ -352,13 +391,16 @@ llvm::Value *ArrayHeapLayout::getAllocationSize(IRGenFunction &IGF,
352391 bool overflow = false ;
353392
354393 // Scale the length by the element stride.
355- llvm::APInt elementStride (sizeWidth, ElementTI.getFixedStride ().getValue ());
394+ llvm::APInt elementStride (sizeWidth,
395+ fixedElementTI.getFixedStride ().getValue ());
356396 assert (elementStride);
357397 auto scaledLength = lenval.umul_ov (elementStride, overflow);
358398 if (overflow) return getSizeMax (IGF);
359399
360400 // Add the header size in.
361- llvm::APInt headerSize (sizeWidth, HeaderSize.getValue ());
401+ assert (isa<llvm::ConstantInt>(layout.HeaderSize ) &&
402+ " fixed-size array element type without constant header size?" );
403+ auto &headerSize = cast<llvm::ConstantInt>(layout.HeaderSize )->getValue ();
362404 auto lengthWithHeader = scaledLength.uadd_ov (headerSize, overflow);
363405 if (overflow) return getSizeMax (IGF);
364406
@@ -396,9 +438,8 @@ llvm::Value *ArrayHeapLayout::getAllocationSize(IRGenFunction &IGF,
396438
397439 // If the element size is known to be zero, we don't need to do
398440 // anything further.
399- llvm::Value *headerSize = getSize (IGF, HeaderSize);
400- if (ElementTI.isEmpty (ResilienceScope::Local))
401- return headerSize;
441+ if (ElementTI.isKnownEmpty ())
442+ return layout.HeaderSize ;
402443
403444 llvm::Value *size = properLength;
404445
@@ -414,68 +455,81 @@ llvm::Value *ArrayHeapLayout::getAllocationSize(IRGenFunction &IGF,
414455 // Increase that by the header size, saturating at SIZE_MAX.
415456 if (canOverflow) {
416457 size = checkOverflow (IGF, llvm::Intrinsic::uadd_with_overflow,
417- size, headerSize );
458+ size, layout. HeaderSize );
418459 } else {
419- size = IGF.Builder .CreateAdd (size, headerSize );
460+ size = IGF.Builder .CreateAdd (size, layout. HeaderSize );
420461 }
421462
422463 return size;
423464}
424465
425466// / Returns a pointer to the 'length' field of an array allocation.
426- Address ArrayHeapLayout::getLengthPointer (IRGenFunction &IGF,
427- llvm::Value *alloc) const {
467+ Address HeapArrayInfo::getLengthPointer (IRGenFunction &IGF,
468+ const Layout &layout,
469+ llvm::Value *alloc) const {
428470 assert (alloc->getType () == IGF.IGM .RefCountedPtrTy );
429471 llvm::Value *addr = IGF.Builder .CreateConstInBoundsGEP1_32 (alloc, 1 );
430472 addr = IGF.Builder .CreateBitCast (addr, IGF.IGM .SizeTy ->getPointerTo ());
431473
432474 return Address (addr, IGF.IGM .getPointerAlignment ());
433475}
434476
435- llvm::Value *ArrayHeapLayout::getBeginPointer (IRGenFunction &IGF,
436- llvm::Value *alloc) const {
477+ llvm::Value *HeapArrayInfo::getBeginPointer (IRGenFunction &IGF,
478+ const Layout &layout,
479+ llvm::Value *alloc) const {
437480 assert (alloc->getType () == IGF.IGM .RefCountedPtrTy );
438481 alloc = IGF.Builder .CreateBitCast (alloc, IGF.IGM .Int8PtrTy );
439- llvm::Value *begin =
440- IGF.Builder .CreateConstInBoundsGEP1_32 (alloc, HeaderSize.getValue ());
482+ llvm::Value *begin = IGF.Builder .CreateInBoundsGEP (alloc, layout.HeaderSize );
441483 return IGF.Builder .CreateBitCast (begin,
442484 ElementTI.getStorageType ()->getPointerTo ());
443485}
444486
445- llvm::Value *ArrayHeapLayout ::emitUnmanagedAlloc (IRGenFunction &IGF,
446- llvm::Value *length,
447- Address &begin,
448- Expr *init,
449- const llvm::Twine &name) const
487+ llvm::Value *HeapArrayInfo ::emitUnmanagedAlloc (IRGenFunction &IGF,
488+ llvm::Value *length,
489+ Address &begin,
490+ Expr *init,
491+ const llvm::Twine &name) const
450492{
493+ Layout layout = getLayout (IGF);
494+
451495 llvm::Constant *metadata = getPrivateMetadata (IGF.IGM );
452- llvm::Value *size = getAllocationSize (IGF, length, true , true );
453- llvm::Value *align = getSize (IGF, Size (Align. getValue ())) ;
496+ llvm::Value *size = getAllocationSize (IGF, layout, length, true , true );
497+ llvm::Value *align = layout. AllocAlign ;
454498
455499 // Perform the allocation.
456500 llvm::Value *alloc =
457501 IGF.emitAllocObjectCall (metadata, size, align, " array.alloc" );
458502
459503 if (!Bindings.empty ()) {
460504 Address bindingsBuffer =
461- projectBindingsBuffer (IGF, Address (alloc, getAlignment () ));
505+ projectBindingsBuffer (IGF, Address (alloc, layout. BestStaticAlignment ));
462506 Bindings.save (IGF, bindingsBuffer);
463507 }
464508
509+ // Store the length pointer to the array.
510+ Address lengthPtr = getLengthPointer (IGF, layout, alloc);
511+ // FIXME: storing the actual length here doesn't seem to work.
512+ IGF.Builder .CreateStore (IGF.IGM .getSize (Size (0 )), lengthPtr);
513+
465514 // Find the begin pointer.
466- llvm::Value *beginPtr = getBeginPointer (IGF, alloc);
515+ llvm::Value *beginPtr = getBeginPointer (IGF, layout, alloc);
467516 begin = ElementTI.getAddressForPointer (beginPtr);
468517
469518 // If we don't have an initializer, just zero-initialize and
470519 // immediately enter a release cleanup.
471520 if (!init) {
472- llvm::Value *sizeToMemset =
473- IGF.Builder .CreateSub (size, getSize (IGF, HeaderSize));
521+ llvm::Value *sizeToMemset = IGF.Builder .CreateSub (size, layout.HeaderSize );
522+
523+ Alignment arrayAlignment = layout.BestStaticAlignment ;
524+ if (auto offset = dyn_cast<llvm::ConstantInt>(layout.HeaderSize ))
525+ arrayAlignment =
526+ arrayAlignment.alignmentAtOffset (Size (offset->getZExtValue ()));
527+
474528 IGF.Builder .CreateMemSet (
475529 IGF.Builder .CreateBitCast (beginPtr, IGF.IGM .Int8PtrTy ),
476530 llvm::ConstantInt::get (IGF.IGM .Int8Ty , 0 ),
477531 sizeToMemset,
478- Align. alignmentAtOffset (HeaderSize) .getValue (),
532+ arrayAlignment .getValue (),
479533 /* volatile*/ false );
480534
481535 // Otherwise, repeatedly evaluate the initializer into successive
@@ -487,11 +541,11 @@ llvm::Value *ArrayHeapLayout::emitUnmanagedAlloc(IRGenFunction &IGF,
487541 return alloc;
488542}
489543
490- ManagedValue ArrayHeapLayout ::emitAlloc (IRGenFunction &IGF,
491- llvm::Value *length,
492- Address &begin,
493- Expr *init,
494- const llvm::Twine &name) const {
544+ ManagedValue HeapArrayInfo ::emitAlloc (IRGenFunction &IGF,
545+ llvm::Value *length,
546+ Address &begin,
547+ Expr *init,
548+ const llvm::Twine &name) const {
495549 llvm::Value *alloc = emitUnmanagedAlloc (IGF, length, begin, init, name);
496550 return IGF.enterReleaseCleanup (alloc);
497551}
0 commit comments