Import compiler-rt r117047.

This commit is contained in:
ed 2010-10-21 19:02:02 +00:00
commit 653bb67455
471 changed files with 184040 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*~
Debug
Release
Profile

59
BlocksRuntime/Block.h Normal file
View File

@ -0,0 +1,59 @@
/*
* Block.h
*
* Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifndef _BLOCK_H_
#define _BLOCK_H_
#if !defined(BLOCK_EXPORT)
# if defined(__cplusplus)
# define BLOCK_EXPORT extern "C"
# else
# define BLOCK_EXPORT extern
# endif
#endif
#if defined(__cplusplus)
extern "C" {
#endif
/* Create a heap based copy of a Block or simply add a reference to an existing one.
* This must be paired with Block_release to recover memory, even when running
* under Objective-C Garbage Collection.
*/
BLOCK_EXPORT void *_Block_copy(const void *aBlock);
/* Lose the reference, and if heap based and last reference, recover the memory. */
BLOCK_EXPORT void _Block_release(const void *aBlock);
#if defined(__cplusplus)
}
#endif
/* Type correct macros. */
#define Block_copy(...) ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__)))
#define Block_release(...) _Block_release((const void *)(__VA_ARGS__))
#endif

View File

@ -0,0 +1,179 @@
/*
* Block_private.h
*
* Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#ifndef _BLOCK_PRIVATE_H_
#define _BLOCK_PRIVATE_H_
#if !defined(BLOCK_EXPORT)
# if defined(__cplusplus)
# define BLOCK_EXPORT extern "C"
# else
# define BLOCK_EXPORT extern
# endif
#endif
#ifndef _MSC_VER
#include <stdbool.h>
#else
/* MSVC doesn't have <stdbool.h>. Compensate. */
typedef char bool;
#define true (bool)1
#define false (bool)0
#endif
#if defined(__cplusplus)
extern "C" {
#endif
enum {
BLOCK_REFCOUNT_MASK = (0xffff),
BLOCK_NEEDS_FREE = (1 << 24),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_HAS_CTOR = (1 << 26), /* Helpers have C++ code. */
BLOCK_IS_GC = (1 << 27),
BLOCK_IS_GLOBAL = (1 << 28),
BLOCK_HAS_DESCRIPTOR = (1 << 29)
};
/* Revised new layout. */
struct Block_descriptor {
unsigned long int reserved;
unsigned long int size;
void (*copy)(void *dst, void *src);
void (*dispose)(void *);
};
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
/* Imported variables. */
};
struct Block_byref {
void *isa;
struct Block_byref *forwarding;
int flags; /* refcount; */
int size;
void (*byref_keep)(struct Block_byref *dst, struct Block_byref *src);
void (*byref_destroy)(struct Block_byref *);
/* long shared[0]; */
};
struct Block_byref_header {
void *isa;
struct Block_byref *forwarding;
int flags;
int size;
};
/* Runtime support functions used by compiler when generating copy/dispose helpers. */
enum {
/* See function implementation for a more complete description of these fields and combinations */
BLOCK_FIELD_IS_OBJECT = 3, /* id, NSObject, __attribute__((NSObject)), block, ... */
BLOCK_FIELD_IS_BLOCK = 7, /* a block variable */
BLOCK_FIELD_IS_BYREF = 8, /* the on stack structure holding the __block variable */
BLOCK_FIELD_IS_WEAK = 16, /* declared __weak, only used in byref copy helpers */
BLOCK_BYREF_CALLER = 128 /* called from __block (byref) copy/dispose support routines. */
};
/* Runtime entry point called by compiler when assigning objects inside copy helper routines */
BLOCK_EXPORT void _Block_object_assign(void *destAddr, const void *object, const int flags);
/* BLOCK_FIELD_IS_BYREF is only used from within block copy helpers */
/* runtime entry point called by the compiler when disposing of objects inside dispose helper routine */
BLOCK_EXPORT void _Block_object_dispose(const void *object, const int flags);
/* Other support functions */
/* Runtime entry to get total size of a closure */
BLOCK_EXPORT unsigned long int Block_size(void *block_basic);
/* the raw data space for runtime classes for blocks */
/* class+meta used for stack, malloc, and collectable based blocks */
BLOCK_EXPORT void * _NSConcreteStackBlock[32];
BLOCK_EXPORT void * _NSConcreteMallocBlock[32];
BLOCK_EXPORT void * _NSConcreteAutoBlock[32];
BLOCK_EXPORT void * _NSConcreteFinalizingBlock[32];
BLOCK_EXPORT void * _NSConcreteGlobalBlock[32];
BLOCK_EXPORT void * _NSConcreteWeakBlockVariable[32];
/* the intercept routines that must be used under GC */
BLOCK_EXPORT void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
void (*setHasRefcount)(const void *, const bool),
void (*gc_assign_strong)(void *, void **),
void (*gc_assign_weak)(const void *, void *),
void (*gc_memmove)(void *, void *, unsigned long));
/* earlier version, now simply transitional */
BLOCK_EXPORT void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
void (*setHasRefcount)(const void *, const bool),
void (*gc_assign_strong)(void *, void **),
void (*gc_assign_weak)(const void *, void *));
BLOCK_EXPORT void _Block_use_RR( void (*retain)(const void *),
void (*release)(const void *));
/* make a collectable GC heap based Block. Not useful under non-GC. */
BLOCK_EXPORT void *_Block_copy_collectable(const void *aBlock);
/* thread-unsafe diagnostic */
BLOCK_EXPORT const char *_Block_dump(const void *block);
/* Obsolete */
/* first layout */
struct Block_basic {
void *isa;
int Block_flags; /* int32_t */
int Block_size; /* XXX should be packed into Block_flags */
void (*Block_invoke)(void *);
void (*Block_copy)(void *dst, void *src); /* iff BLOCK_HAS_COPY_DISPOSE */
void (*Block_dispose)(void *); /* iff BLOCK_HAS_COPY_DISPOSE */
/* long params[0]; // where const imports, __block storage references, etc. get laid down */
};
#if defined(__cplusplus)
}
#endif
#endif /* _BLOCK_PRIVATE_H_ */

View File

@ -0,0 +1,13 @@
PROJECT( BlocksRuntime C )
SET( SRCS
runtime.c
data.c
)
ADD_LIBRARY( ${PROJECT_NAME} SHARED ${SRCS})
SET_TARGET_PROPERTIES( ${PROJECT_NAME} PROPERTIES
INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib )
INSTALL( TARGETS ${PROJECT_NAME} DESTINATION lib )
INSTALL( FILES Block.h Block_private.h DESTINATION include )

41
BlocksRuntime/data.c Normal file
View File

@ -0,0 +1,41 @@
/*
* data.c
*
* Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
/********************
NSBlock support
We allocate space and export a symbol to be used as the Class for the on-stack and malloc'ed copies until ObjC arrives on the scene. These data areas are set up by Foundation to link in as real classes post facto.
We keep these in a separate file so that we can include the runtime code in test subprojects but not include the data so that compiled code that sees the data in libSystem doesn't get confused by a second copy. Somehow these don't get unified in a common block.
**********************/
void * _NSConcreteStackBlock[32] = { 0 };
void * _NSConcreteMallocBlock[32] = { 0 };
void * _NSConcreteAutoBlock[32] = { 0 };
void * _NSConcreteFinalizingBlock[32] = { 0 };
void * _NSConcreteGlobalBlock[32] = { 0 };
void * _NSConcreteWeakBlockVariable[32] = { 0 };
void _Block_copy_error(void) {
}

700
BlocksRuntime/runtime.c Normal file
View File

@ -0,0 +1,700 @@
/*
* runtime.c
*
* Copyright 2008-2010 Apple, Inc. Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to permit
* persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include "Block_private.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "config.h"
#ifdef HAVE_AVAILABILITY_MACROS_H
#include <AvailabilityMacros.h>
#endif /* HAVE_AVAILABILITY_MACROS_H */
#ifdef HAVE_TARGET_CONDITIONALS_H
#include <TargetConditionals.h>
#endif /* HAVE_TARGET_CONDITIONALS_H */
#if defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_INT) && defined(HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG)
#ifdef HAVE_LIBKERN_OSATOMIC_H
#include <libkern/OSAtomic.h>
#endif /* HAVE_LIBKERN_OSATOMIC_H */
#elif defined(__WIN32__) || defined(_WIN32)
#define _CRT_SECURE_NO_WARNINGS 1
#include <windows.h>
static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
/* fixme barrier is overkill -- see objc-os.h */
long original = InterlockedCompareExchange(dst, newl, oldl);
return (original == oldl);
}
static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
/* fixme barrier is overkill -- see objc-os.h */
int original = InterlockedCompareExchange(dst, newi, oldi);
return (original == oldi);
}
/*
* Check to see if the GCC atomic built-ins are available. If we're on
* a 64-bit system, make sure we have an 8-byte atomic function
* available.
*
*/
#elif defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT) && defined(HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG)
static __inline bool OSAtomicCompareAndSwapLong(long oldl, long newl, long volatile *dst) {
return __sync_bool_compare_and_swap(dst, oldl, newl);
}
static __inline bool OSAtomicCompareAndSwapInt(int oldi, int newi, int volatile *dst) {
return __sync_bool_compare_and_swap(dst, oldi, newi);
}
#else
#error unknown atomic compare-and-swap primitive
#endif /* HAVE_OSATOMIC_COMPARE_AND_SWAP_INT && HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG */
/*
* Globals:
*/
static void *_Block_copy_class = _NSConcreteMallocBlock;
static void *_Block_copy_finalizing_class = _NSConcreteMallocBlock;
static int _Block_copy_flag = BLOCK_NEEDS_FREE;
static int _Byref_flag_initial_value = BLOCK_NEEDS_FREE | 2;
static const int WANTS_ONE = (1 << 16);
static bool isGC = false;
/*
* Internal Utilities:
*/
#if 0
static unsigned long int latching_incr_long(unsigned long int *where) {
while (1) {
unsigned long int old_value = *(volatile unsigned long int *)where;
if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
return BLOCK_REFCOUNT_MASK;
}
if (OSAtomicCompareAndSwapLong(old_value, old_value+1, (volatile long int *)where)) {
return old_value+1;
}
}
}
#endif /* if 0 */
static int latching_incr_int(int *where) {
while (1) {
int old_value = *(volatile int *)where;
if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
return BLOCK_REFCOUNT_MASK;
}
if (OSAtomicCompareAndSwapInt(old_value, old_value+1, (volatile int *)where)) {
return old_value+1;
}
}
}
#if 0
static int latching_decr_long(unsigned long int *where) {
while (1) {
unsigned long int old_value = *(volatile int *)where;
if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
return BLOCK_REFCOUNT_MASK;
}
if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
return 0;
}
if (OSAtomicCompareAndSwapLong(old_value, old_value-1, (volatile long int *)where)) {
return old_value-1;
}
}
}
#endif /* if 0 */
static int latching_decr_int(int *where) {
while (1) {
int old_value = *(volatile int *)where;
if ((old_value & BLOCK_REFCOUNT_MASK) == BLOCK_REFCOUNT_MASK) {
return BLOCK_REFCOUNT_MASK;
}
if ((old_value & BLOCK_REFCOUNT_MASK) == 0) {
return 0;
}
if (OSAtomicCompareAndSwapInt(old_value, old_value-1, (volatile int *)where)) {
return old_value-1;
}
}
}
/*
* GC support stub routines:
*/
#if 0
#pragma mark GC Support Routines
#endif /* if 0 */
static void *_Block_alloc_default(const unsigned long size, const bool initialCountIsOne, const bool isObject) {
return malloc(size);
}
static void _Block_assign_default(void *value, void **destptr) {
*destptr = value;
}
static void _Block_setHasRefcount_default(const void *ptr, const bool hasRefcount) {
}
static void _Block_do_nothing(const void *aBlock) { }
static void _Block_retain_object_default(const void *ptr) {
if (!ptr) return;
}
static void _Block_release_object_default(const void *ptr) {
if (!ptr) return;
}
static void _Block_assign_weak_default(const void *ptr, void *dest) {
*(void **)dest = (void *)ptr;
}
static void _Block_memmove_default(void *dst, void *src, unsigned long size) {
memmove(dst, src, (size_t)size);
}
static void _Block_memmove_gc_broken(void *dest, void *src, unsigned long size) {
void **destp = (void **)dest;
void **srcp = (void **)src;
while (size) {
_Block_assign_default(*srcp, destp);
destp++;
srcp++;
size -= sizeof(void *);
}
}
/*
* GC support callout functions - initially set to stub routines:
*/
static void *(*_Block_allocator)(const unsigned long, const bool isOne, const bool isObject) = _Block_alloc_default;
static void (*_Block_deallocator)(const void *) = (void (*)(const void *))free;
static void (*_Block_assign)(void *value, void **destptr) = _Block_assign_default;
static void (*_Block_setHasRefcount)(const void *ptr, const bool hasRefcount) = _Block_setHasRefcount_default;
static void (*_Block_retain_object)(const void *ptr) = _Block_retain_object_default;
static void (*_Block_release_object)(const void *ptr) = _Block_release_object_default;
static void (*_Block_assign_weak)(const void *dest, void *ptr) = _Block_assign_weak_default;
static void (*_Block_memmove)(void *dest, void *src, unsigned long size) = _Block_memmove_default;
/*
* GC support SPI functions - called from ObjC runtime and CoreFoundation:
*/
/* Public SPI
* Called from objc-auto to turn on GC.
* version 3, 4 arg, but changed 1st arg
*/
void _Block_use_GC( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
void (*setHasRefcount)(const void *, const bool),
void (*gc_assign)(void *, void **),
void (*gc_assign_weak)(const void *, void *),
void (*gc_memmove)(void *, void *, unsigned long)) {
isGC = true;
_Block_allocator = alloc;
_Block_deallocator = _Block_do_nothing;
_Block_assign = gc_assign;
_Block_copy_flag = BLOCK_IS_GC;
_Block_copy_class = _NSConcreteAutoBlock;
/* blocks with ctors & dtors need to have the dtor run from a class with a finalizer */
_Block_copy_finalizing_class = _NSConcreteFinalizingBlock;
_Block_setHasRefcount = setHasRefcount;
_Byref_flag_initial_value = BLOCK_IS_GC; // no refcount
_Block_retain_object = _Block_do_nothing;
_Block_release_object = _Block_do_nothing;
_Block_assign_weak = gc_assign_weak;
_Block_memmove = gc_memmove;
}
/* transitional */
void _Block_use_GC5( void *(*alloc)(const unsigned long, const bool isOne, const bool isObject),
void (*setHasRefcount)(const void *, const bool),
void (*gc_assign)(void *, void **),
void (*gc_assign_weak)(const void *, void *)) {
/* until objc calls _Block_use_GC it will call us; supply a broken internal memmove implementation until then */
_Block_use_GC(alloc, setHasRefcount, gc_assign, gc_assign_weak, _Block_memmove_gc_broken);
}
/*
* Called from objc-auto to alternatively turn on retain/release.
* Prior to this the only "object" support we can provide is for those
* super special objects that live in libSystem, namely dispatch queues.
* Blocks and Block_byrefs have their own special entry points.
*
*/
void _Block_use_RR( void (*retain)(const void *),
void (*release)(const void *)) {
_Block_retain_object = retain;
_Block_release_object = release;
}
/*
* Internal Support routines for copying:
*/
#if 0
#pragma mark Copy/Release support
#endif /* if 0 */
/* Copy, or bump refcount, of a block. If really copying, call the copy helper if present. */
static void *_Block_copy_internal(const void *arg, const int flags) {
struct Block_layout *aBlock;
const bool wantsOne = (WANTS_ONE & flags) == WANTS_ONE;
//printf("_Block_copy_internal(%p, %x)\n", arg, flags);
if (!arg) return NULL;
// The following would be better done as a switch statement
aBlock = (struct Block_layout *)arg;
if (aBlock->flags & BLOCK_NEEDS_FREE) {
// latches on high
latching_incr_int(&aBlock->flags);
return aBlock;
}
else if (aBlock->flags & BLOCK_IS_GC) {
// GC refcounting is expensive so do most refcounting here.
if (wantsOne && ((latching_incr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK) == 1)) {
// Tell collector to hang on this - it will bump the GC refcount version
_Block_setHasRefcount(aBlock, true);
}
return aBlock;
}
else if (aBlock->flags & BLOCK_IS_GLOBAL) {
return aBlock;
}
// Its a stack block. Make a copy.
if (!isGC) {
struct Block_layout *result = malloc(aBlock->descriptor->size);
if (!result) return (void *)0;
memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
// reset refcount
result->flags &= ~(BLOCK_REFCOUNT_MASK); // XXX not needed
result->flags |= BLOCK_NEEDS_FREE | 1;
result->isa = _NSConcreteMallocBlock;
if (result->flags & BLOCK_HAS_COPY_DISPOSE) {
//printf("calling block copy helper %p(%p, %p)...\n", aBlock->descriptor->copy, result, aBlock);
(*aBlock->descriptor->copy)(result, aBlock); // do fixup
}
return result;
}
else {
// Under GC want allocation with refcount 1 so we ask for "true" if wantsOne
// This allows the copy helper routines to make non-refcounted block copies under GC
unsigned long int flags = aBlock->flags;
bool hasCTOR = (flags & BLOCK_HAS_CTOR) != 0;
struct Block_layout *result = _Block_allocator(aBlock->descriptor->size, wantsOne, hasCTOR);
if (!result) return (void *)0;
memmove(result, aBlock, aBlock->descriptor->size); // bitcopy first
// reset refcount
// if we copy a malloc block to a GC block then we need to clear NEEDS_FREE.
flags &= ~(BLOCK_NEEDS_FREE|BLOCK_REFCOUNT_MASK); // XXX not needed
if (wantsOne)
flags |= BLOCK_IS_GC | 1;
else
flags |= BLOCK_IS_GC;
result->flags = flags;
if (flags & BLOCK_HAS_COPY_DISPOSE) {
//printf("calling block copy helper...\n");
(*aBlock->descriptor->copy)(result, aBlock); // do fixup
}
if (hasCTOR) {
result->isa = _NSConcreteFinalizingBlock;
}
else {
result->isa = _NSConcreteAutoBlock;
}
return result;
}
}
/*
* Runtime entry points for maintaining the sharing knowledge of byref data blocks.
*
* A closure has been copied and its fixup routine is asking us to fix up the reference to the shared byref data
* Closures that aren't copied must still work, so everyone always accesses variables after dereferencing the forwarding ptr.
* We ask if the byref pointer that we know about has already been copied to the heap, and if so, increment it.
* Otherwise we need to copy it and update the stack forwarding pointer
* XXX We need to account for weak/nonretained read-write barriers.
*/
static void _Block_byref_assign_copy(void *dest, const void *arg, const int flags) {
struct Block_byref **destp = (struct Block_byref **)dest;
struct Block_byref *src = (struct Block_byref *)arg;
//printf("_Block_byref_assign_copy called, byref destp %p, src %p, flags %x\n", destp, src, flags);
//printf("src dump: %s\n", _Block_byref_dump(src));
if (src->forwarding->flags & BLOCK_IS_GC) {
; // don't need to do any more work
}
else if ((src->forwarding->flags & BLOCK_REFCOUNT_MASK) == 0) {
//printf("making copy\n");
// src points to stack
bool isWeak = ((flags & (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK)) == (BLOCK_FIELD_IS_BYREF|BLOCK_FIELD_IS_WEAK));
// if its weak ask for an object (only matters under GC)
struct Block_byref *copy = (struct Block_byref *)_Block_allocator(src->size, false, isWeak);
copy->flags = src->flags | _Byref_flag_initial_value; // non-GC one for caller, one for stack
copy->forwarding = copy; // patch heap copy to point to itself (skip write-barrier)
src->forwarding = copy; // patch stack to point to heap copy
copy->size = src->size;
if (isWeak) {
copy->isa = &_NSConcreteWeakBlockVariable; // mark isa field so it gets weak scanning
}
if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
// Trust copy helper to copy everything of interest
// If more than one field shows up in a byref block this is wrong XXX
copy->byref_keep = src->byref_keep;
copy->byref_destroy = src->byref_destroy;
(*src->byref_keep)(copy, src);
}
else {
// just bits. Blast 'em using _Block_memmove in case they're __strong
_Block_memmove(
(void *)&copy->byref_keep,
(void *)&src->byref_keep,
src->size - sizeof(struct Block_byref_header));
}
}
// already copied to heap
else if ((src->forwarding->flags & BLOCK_NEEDS_FREE) == BLOCK_NEEDS_FREE) {
latching_incr_int(&src->forwarding->flags);
}
// assign byref data block pointer into new Block
_Block_assign(src->forwarding, (void **)destp);
}
// Old compiler SPI
static void _Block_byref_release(const void *arg) {
struct Block_byref *shared_struct = (struct Block_byref *)arg;
int refcount;
// dereference the forwarding pointer since the compiler isn't doing this anymore (ever?)
shared_struct = shared_struct->forwarding;
//printf("_Block_byref_release %p called, flags are %x\n", shared_struct, shared_struct->flags);
// To support C++ destructors under GC we arrange for there to be a finalizer for this
// by using an isa that directs the code to a finalizer that calls the byref_destroy method.
if ((shared_struct->flags & BLOCK_NEEDS_FREE) == 0) {
return; // stack or GC or global
}
refcount = shared_struct->flags & BLOCK_REFCOUNT_MASK;
if (refcount <= 0) {
printf("_Block_byref_release: Block byref data structure at %p underflowed\n", arg);
}
else if ((latching_decr_int(&shared_struct->flags) & BLOCK_REFCOUNT_MASK) == 0) {
//printf("disposing of heap based byref block\n");
if (shared_struct->flags & BLOCK_HAS_COPY_DISPOSE) {
//printf("calling out to helper\n");
(*shared_struct->byref_destroy)(shared_struct);
}
_Block_deallocator((struct Block_layout *)shared_struct);
}
}
/*
*
* API supporting SPI
* _Block_copy, _Block_release, and (old) _Block_destroy
*
*/
#if 0
#pragma mark SPI/API
#endif /* if 0 */
void *_Block_copy(const void *arg) {
return _Block_copy_internal(arg, WANTS_ONE);
}
// API entry point to release a copied Block
void _Block_release(void *arg) {
struct Block_layout *aBlock = (struct Block_layout *)arg;
int32_t newCount;
if (!aBlock) return;
newCount = latching_decr_int(&aBlock->flags) & BLOCK_REFCOUNT_MASK;
if (newCount > 0) return;
// Hit zero
if (aBlock->flags & BLOCK_IS_GC) {
// Tell GC we no longer have our own refcounts. GC will decr its refcount
// and unless someone has done a CFRetain or marked it uncollectable it will
// now be subject to GC reclamation.
_Block_setHasRefcount(aBlock, false);
}
else if (aBlock->flags & BLOCK_NEEDS_FREE) {
if (aBlock->flags & BLOCK_HAS_COPY_DISPOSE)(*aBlock->descriptor->dispose)(aBlock);
_Block_deallocator(aBlock);
}
else if (aBlock->flags & BLOCK_IS_GLOBAL) {
;
}
else {
printf("Block_release called upon a stack Block: %p, ignored\n", (void *)aBlock);
}
}
// Old Compiler SPI point to release a copied Block used by the compiler in dispose helpers
static void _Block_destroy(const void *arg) {
struct Block_layout *aBlock;
if (!arg) return;
aBlock = (struct Block_layout *)arg;
if (aBlock->flags & BLOCK_IS_GC) {
// assert(aBlock->Block_flags & BLOCK_HAS_CTOR);
return; // ignore, we are being called because of a DTOR
}
_Block_release(aBlock);
}
/*
*
* SPI used by other layers
*
*/
// SPI, also internal. Called from NSAutoBlock only under GC
void *_Block_copy_collectable(const void *aBlock) {
return _Block_copy_internal(aBlock, 0);
}
// SPI
unsigned long int Block_size(void *arg) {
return ((struct Block_layout *)arg)->descriptor->size;
}
#if 0
#pragma mark Compiler SPI entry points
#endif /* if 0 */
/*******************************************************
Entry points used by the compiler - the real API!
A Block can reference four different kinds of things that require help when the Block is copied to the heap.
1) C++ stack based objects
2) References to Objective-C objects
3) Other Blocks
4) __block variables
In these cases helper functions are synthesized by the compiler for use in Block_copy and Block_release, called the copy and dispose helpers. The copy helper emits a call to the C++ const copy constructor for C++ stack based objects and for the rest calls into the runtime support function _Block_object_assign. The dispose helper has a call to the C++ destructor for case 1 and a call into _Block_object_dispose for the rest.
The flags parameter of _Block_object_assign and _Block_object_dispose is set to
* BLOCK_FIELD_IS_OBJECT (3), for the case of an Objective-C Object,
* BLOCK_FIELD_IS_BLOCK (7), for the case of another Block, and
* BLOCK_FIELD_IS_BYREF (8), for the case of a __block variable.
If the __block variable is marked weak the compiler also or's in BLOCK_FIELD_IS_WEAK (16).
So the Block copy/dispose helpers should only ever generate the four flag values of 3, 7, 8, and 24.
When a __block variable is either a C++ object, an Objective-C object, or another Block then the compiler also generates copy/dispose helper functions. Similarly to the Block copy helper, the "__block" copy helper (formerly and still a.k.a. "byref" copy helper) will do a C++ copy constructor (not a const one though!) and the dispose helper will do the destructor. And similarly the helpers will call into the same two support functions with the same values for objects and Blocks with the additional BLOCK_BYREF_CALLER (128) bit of information supplied.
So the __block copy/dispose helpers will generate flag values of 3 or 7 for objects and Blocks respectively, with BLOCK_FIELD_IS_WEAK (16) or'ed as appropriate and always 128 or'd in, for the following set of possibilities:
__block id 128+3
__weak block id 128+3+16
__block (^Block) 128+7
__weak __block (^Block) 128+7+16
The implementation of the two routines would be improved by switch statements enumerating the eight cases.
********************************************************/
/*
* When Blocks or Block_byrefs hold objects then their copy routine helpers use this entry point
* to do the assignment.
*/
void _Block_object_assign(void *destAddr, const void *object, const int flags) {
//printf("_Block_object_assign(*%p, %p, %x)\n", destAddr, object, flags);
if ((flags & BLOCK_BYREF_CALLER) == BLOCK_BYREF_CALLER) {
if ((flags & BLOCK_FIELD_IS_WEAK) == BLOCK_FIELD_IS_WEAK) {
_Block_assign_weak(object, destAddr);
}
else {
// do *not* retain or *copy* __block variables whatever they are
_Block_assign((void *)object, destAddr);
}
}
else if ((flags & BLOCK_FIELD_IS_BYREF) == BLOCK_FIELD_IS_BYREF) {
// copying a __block reference from the stack Block to the heap
// flags will indicate if it holds a __weak reference and needs a special isa
_Block_byref_assign_copy(destAddr, object, flags);
}
// (this test must be before next one)
else if ((flags & BLOCK_FIELD_IS_BLOCK) == BLOCK_FIELD_IS_BLOCK) {
// copying a Block declared variable from the stack Block to the heap
_Block_assign(_Block_copy_internal(object, flags), destAddr);
}
// (this test must be after previous one)
else if ((flags & BLOCK_FIELD_IS_OBJECT) == BLOCK_FIELD_IS_OBJECT) {
//printf("retaining object at %p\n", object);
_Block_retain_object(object);
//printf("done retaining object at %p\n", object);
_Block_assign((void *)object, destAddr);
}
}
// When Blocks or Block_byrefs hold objects their destroy helper routines call this entry point
// to help dispose of the contents
// Used initially only for __attribute__((NSObject)) marked pointers.
void _Block_object_dispose(const void *object, const int flags) {
//printf("_Block_object_dispose(%p, %x)\n", object, flags);
if (flags & BLOCK_FIELD_IS_BYREF) {
// get rid of the __block data structure held in a Block
_Block_byref_release(object);
}
else if ((flags & (BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_BLOCK) {
// get rid of a referenced Block held by this Block
// (ignore __block Block variables, compiler doesn't need to call us)
_Block_destroy(object);
}
else if ((flags & (BLOCK_FIELD_IS_WEAK|BLOCK_FIELD_IS_BLOCK|BLOCK_BYREF_CALLER)) == BLOCK_FIELD_IS_OBJECT) {
// get rid of a referenced object held by this Block
// (ignore __block object variables, compiler doesn't need to call us)
_Block_release_object(object);
}
}
/*
* Debugging support:
*/
#if 0
#pragma mark Debugging
#endif /* if 0 */
const char *_Block_dump(const void *block) {
struct Block_layout *closure = (struct Block_layout *)block;
static char buffer[512];
char *cp = buffer;
if (closure == NULL) {
sprintf(cp, "NULL passed to _Block_dump\n");
return buffer;
}
if (! (closure->flags & BLOCK_HAS_DESCRIPTOR)) {
printf("Block compiled by obsolete compiler, please recompile source for this Block\n");
exit(1);
}
cp += sprintf(cp, "^%p (new layout) =\n", (void *)closure);
if (closure->isa == NULL) {
cp += sprintf(cp, "isa: NULL\n");
}
else if (closure->isa == _NSConcreteStackBlock) {
cp += sprintf(cp, "isa: stack Block\n");
}
else if (closure->isa == _NSConcreteMallocBlock) {
cp += sprintf(cp, "isa: malloc heap Block\n");
}
else if (closure->isa == _NSConcreteAutoBlock) {
cp += sprintf(cp, "isa: GC heap Block\n");
}
else if (closure->isa == _NSConcreteGlobalBlock) {
cp += sprintf(cp, "isa: global Block\n");
}
else if (closure->isa == _NSConcreteFinalizingBlock) {
cp += sprintf(cp, "isa: finalizing Block\n");
}
else {
cp += sprintf(cp, "isa?: %p\n", (void *)closure->isa);
}
cp += sprintf(cp, "flags:");
if (closure->flags & BLOCK_HAS_DESCRIPTOR) {
cp += sprintf(cp, " HASDESCRIPTOR");
}
if (closure->flags & BLOCK_NEEDS_FREE) {
cp += sprintf(cp, " FREEME");
}
if (closure->flags & BLOCK_IS_GC) {
cp += sprintf(cp, " ISGC");
}
if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
cp += sprintf(cp, " HASHELP");
}
if (closure->flags & BLOCK_HAS_CTOR) {
cp += sprintf(cp, " HASCTOR");
}
cp += sprintf(cp, "\nrefcount: %u\n", closure->flags & BLOCK_REFCOUNT_MASK);
cp += sprintf(cp, "invoke: %p\n", (void *)(uintptr_t)closure->invoke);
{
struct Block_descriptor *dp = closure->descriptor;
cp += sprintf(cp, "descriptor: %p\n", (void *)dp);
cp += sprintf(cp, "descriptor->reserved: %lu\n", dp->reserved);
cp += sprintf(cp, "descriptor->size: %lu\n", dp->size);
if (closure->flags & BLOCK_HAS_COPY_DISPOSE) {
cp += sprintf(cp, "descriptor->copy helper: %p\n", (void *)(uintptr_t)dp->copy);
cp += sprintf(cp, "descriptor->dispose helper: %p\n", (void *)(uintptr_t)dp->dispose);
}
}
return buffer;
}
const char *_Block_byref_dump(struct Block_byref *src) {
static char buffer[256];
char *cp = buffer;
cp += sprintf(cp, "byref data block %p contents:\n", (void *)src);
cp += sprintf(cp, " forwarding: %p\n", (void *)src->forwarding);
cp += sprintf(cp, " flags: 0x%x\n", src->flags);
cp += sprintf(cp, " size: %d\n", src->size);
if (src->flags & BLOCK_HAS_COPY_DISPOSE) {
cp += sprintf(cp, " copy helper: %p\n", (void *)(uintptr_t)src->byref_keep);
cp += sprintf(cp, " dispose helper: %p\n", (void *)(uintptr_t)src->byref_destroy);
}
return buffer;
}

View File

@ -0,0 +1,25 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// testfilerunner CONFIG
#include <stdio.h>
int main(int argc, char **argv) {
static int numberOfSquesals = 5;
^{ numberOfSquesals = 6; }();
if (numberOfSquesals == 6) {
printf("%s: success\n", argv[0]);
return 0;
}
printf("**** did not update static local, rdar://6177162\n");
return 1;
}

View File

@ -0,0 +1,51 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* blockimport.c
* testObjects
*
* Created by Blaine Garst on 10/13/08.
*
*/
//
// pure C nothing more needed
// CONFIG rdar://6289344
#include <stdio.h>
#include <Block.h>
#include <Block_private.h>
int main(int argc, char *argv[]) {
int i = 1;
int (^intblock)(void) = ^{ return i*10; };
void (^vv)(void) = ^{
if (argc > 0) {
printf("intblock returns %d\n", intblock());
}
};
#if 0
//printf("Block dump %s\n", _Block_dump(vv));
{
struct Block_layout *layout = (struct Block_layout *)(void *)vv;
printf("isa %p\n", layout->isa);
printf("flags %x\n", layout->flags);
printf("descriptor %p\n", layout->descriptor);
printf("descriptor->size %d\n", layout->descriptor->size);
}
#endif
void (^vvcopy)(void) = Block_copy(vv);
Block_release(vvcopy);
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,34 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// byrefaccess.m
// test that byref access to locals is accurate
// testObjects
//
// Created by Blaine Garst on 5/13/08.
//
// CONFIG
#include <stdio.h>
void callVoidVoid(void (^closure)(void)) {
closure();
}
int main(int argc, char *argv[]) {
__block int i = 10;
callVoidVoid(^{ ++i; });
if (i != 11) {
printf("*** %s didn't update i\n", argv[0]);
return 1;
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,41 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// byrefcopy.m
// testObjects
//
// Created by Blaine Garst on 5/13/08.
//
#include <stdio.h>
#include <Block.h>
#include <Block_private.h>
// CONFIG
void callVoidVoid(void (^closure)(void)) {
closure();
}
int main(int argc, char *argv[]) {
int __block i = 10;
void (^block)(void) = ^{ ++i; };
//printf("original (old style) is %s\n", _Block_dump_old(block));
//printf("original (new style) is %s\n", _Block_dump(block));
void (^blockcopy)(void) = Block_copy(block);
//printf("copy is %s\n", _Block_dump(blockcopy));
// use a copy & see that it updates i
callVoidVoid(block);
if (i != 11) {
printf("*** %s didn't update i\n", argv[0]);
return 1;
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,46 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG rdar://6255170
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <Block.h>
#include <Block_private.h>
#include <assert.h>
int
main(int argc, char *argv[])
{
__block int var = 0;
int shouldbe = 0;
void (^b)(void) = ^{ var++; /*printf("var is at %p with value %d\n", &var, var);*/ };
__typeof(b) _b;
//printf("before copy...\n");
b(); ++shouldbe;
size_t i;
for (i = 0; i < 10; i++) {
_b = Block_copy(b); // make a new copy each time
assert(_b);
++shouldbe;
_b(); // should still update the stack
Block_release(_b);
}
//printf("after...\n");
b(); ++shouldbe;
if (var != shouldbe) {
printf("Hmm, var is %d but should be %d\n", var, shouldbe);
return 1;
}
printf("%s: Success!!\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,32 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#include <Block.h>
#include <stdio.h>
// CONFIG rdar://6225809
// fixed in 5623
int main(int argc, char *argv[]) {
__block int a = 42;
int* ap = &a; // just to keep the address on the stack.
void (^b)(void) = ^{
//a; // workaround, a should be implicitly imported
Block_copy(^{
a = 2;
});
};
Block_copy(b);
if(&a == ap) {
printf("**** __block heap storage should have been created at this point\n");
return 1;
}
printf("%s: Success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,69 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* byrefcopyint.c
* testObjects
*
* Created by Blaine Garst on 12/1/08.
*
*/
//
// byrefcopyid.m
// testObjects
//
// Created by Blaine Garst on 5/13/08.
//
// Tests copying of blocks with byref ints
// CONFIG rdar://6414583 -C99
#include <stdio.h>
#include <string.h>
#include <Block.h>
#include <Block_private.h>
typedef void (^voidVoid)(void);
voidVoid dummy;
void callVoidVoid(voidVoid closure) {
closure();
}
voidVoid testRoutine(const char *whoami) {
__block int dumbo = strlen(whoami);
dummy = ^{
//printf("incring dumbo from %d\n", dumbo);
++dumbo;
};
voidVoid copy = Block_copy(dummy);
return copy;
}
int main(int argc, char *argv[]) {
voidVoid array[100];
for (int i = 0; i < 100; ++i) {
array[i] = testRoutine(argv[0]);
array[i]();
}
for (int i = 0; i < 100; ++i) {
Block_release(array[i]);
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,41 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// byrefcopystack.m
// testObjects
//
// Created by Blaine Garst on 5/13/08.
//
#include <stdio.h>
#include <Block.h>
// CONFIG rdar://6255170
void (^bumpi)(void);
int (^geti)(void);
void setClosures() {
int __block i = 10;
bumpi = Block_copy(^{ ++i; });
geti = Block_copy(^{ return i; });
}
int main(int argc, char *argv[]) {
setClosures();
bumpi();
int i = geti();
if (i != 11) {
printf("*** %s didn't update i\n", argv[0]);
return 1;
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,73 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <Block.h>
int
main(int argc, char *argv[])
{
__block int var = 0;
void (^b)(void) = ^{ var++; };
//sanity(b);
b();
printf("%s: success!\n", argv[0]);
return 0;
}
#if 1
/* replicated internal data structures: BEWARE, MAY CHANGE!!! */
enum {
BLOCK_REFCOUNT_MASK = (0xffff),
BLOCK_NEEDS_FREE = (1 << 24),
BLOCK_HAS_COPY_DISPOSE = (1 << 25),
BLOCK_NO_COPY = (1 << 26), // interim byref: no copies allowed
BLOCK_IS_GC = (1 << 27),
BLOCK_IS_GLOBAL = (1 << 28),
};
struct byref_id {
struct byref_id *forwarding;
int flags;//refcount;
int size;
void (*byref_keep)(struct byref_id *dst, struct byref_id *src);
void (*byref_destroy)(struct byref_id *);
int var;
};
struct Block_basic2 {
void *isa;
int Block_flags; // int32_t
int Block_size; // XXX should be packed into Block_flags
void (*Block_invoke)(void *);
void (*Block_copy)(void *dst, void *src);
void (*Block_dispose)(void *);
struct byref_id *ref;
};
void sanity(void *arg) {
struct Block_basic2 *bb = (struct Block_basic2 *)arg;
if ( ! (bb->Block_flags & BLOCK_HAS_COPY_DISPOSE)) {
printf("missing copy/dispose helpers for byref data\n");
exit(1);
}
struct byref_id *ref = bb->ref;
if (ref->forwarding != ref) {
printf("forwarding pointer should be %p but is %p\n", ref, ref->forwarding);
exit(1);
}
}
#endif

View File

@ -0,0 +1,57 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
// CONFIG
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
typedef struct {
unsigned long ps[30];
int qs[30];
} BobTheStruct;
int main (int argc, const char * argv[]) {
__block BobTheStruct fiddly;
BobTheStruct copy;
void (^incrementFiddly)() = ^{
int i;
for(i=0; i<30; i++) {
fiddly.ps[i]++;
fiddly.qs[i]++;
}
};
memset(&fiddly, 0xA5, sizeof(fiddly));
memset(&copy, 0x2A, sizeof(copy));
int i;
for(i=0; i<30; i++) {
fiddly.ps[i] = i * i * i;
fiddly.qs[i] = -i * i * i;
}
copy = fiddly;
incrementFiddly();
if ( &copy == &fiddly ) {
printf("%s: struct wasn't copied.", argv[0]);
exit(1);
}
for(i=0; i<30; i++) {
//printf("[%d]: fiddly.ps: %lu, copy.ps: %lu, fiddly.qs: %d, copy.qs: %d\n", i, fiddly.ps[i], copy.ps[i], fiddly.qs[i], copy.qs[i]);
if ( (fiddly.ps[i] != copy.ps[i] + 1) || (fiddly.qs[i] != copy.qs[i] + 1) ) {
printf("%s: struct contents were not incremented.", argv[0]);
exit(1);
}
}
printf("%s: success\n", argv[0]);
return 0;
}

20
BlocksRuntime/tests/c99.c Normal file
View File

@ -0,0 +1,20 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// c99.m
//
// CONFIG C99 rdar://problem/6399225
#import <stdio.h>
#import <stdlib.h>
int main(int argc, char *argv[]) {
void (^blockA)(void) = ^ { ; };
blockA();
printf("%s: success\n", argv[0]);
exit(0);
}

View File

@ -0,0 +1,37 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* cast.c
* testObjects
*
* Created by Blaine Garst on 2/17/09.
*
*/
// PURPOSE should allow casting of a Block reference to an arbitrary pointer and back
// CONFIG open
#include <stdio.h>
int main(int argc, char *argv[]) {
void (^aBlock)(void);
int *ip;
char *cp;
double *dp;
ip = (int *)aBlock;
cp = (char *)aBlock;
dp = (double *)aBlock;
aBlock = (void (^)(void))ip;
aBlock = (void (^)(void))cp;
aBlock = (void (^)(void))dp;
printf("%s: success", argv[0]);
return 0;
}

View File

@ -0,0 +1,28 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// constassign.c
// bocktest
//
// Created by Blaine Garst on 3/21/08.
//
// shouldn't be able to assign to a const pointer
// CONFIG error: assignment of read-only
#import <stdio.h>
void foo(void) { printf("I'm in foo\n"); }
void bar(void) { printf("I'm in bar\n"); }
int main(int argc, char *argv[]) {
void (*const fptr)(void) = foo;
void (^const blockA)(void) = ^ { printf("hello\n"); };
blockA = ^ { printf("world\n"); } ;
fptr = bar;
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,29 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG open rdar://6439600
#import <stdio.h>
#import <stdlib.h>
#define NUMBER_OF_BLOCKS 100
int main (int argc, const char * argv[]) {
int (^x[NUMBER_OF_BLOCKS])();
int i;
for(i=0; i<NUMBER_OF_BLOCKS; i++) x[i] = ^{ return i; };
for(i=0; i<NUMBER_OF_BLOCKS; i++) {
if (x[i]() != i) {
printf("%s: failure, %d != %d\n", argv[0], x[i](), i);
exit(1);
}
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,85 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#include <stdio.h>
#include <Block.h>
// CONFIG C++ rdar://6243400,rdar://6289367
int constructors = 0;
int destructors = 0;
#define CONST const
class TestObject
{
public:
TestObject(CONST TestObject& inObj);
TestObject();
~TestObject();
TestObject& operator=(CONST TestObject& inObj);
int version() CONST { return _version; }
private:
mutable int _version;
};
TestObject::TestObject(CONST TestObject& inObj)
{
++constructors;
_version = inObj._version;
//printf("%p (%d) -- TestObject(const TestObject&) called\n", this, _version);
}
TestObject::TestObject()
{
_version = ++constructors;
//printf("%p (%d) -- TestObject() called\n", this, _version);
}
TestObject::~TestObject()
{
//printf("%p -- ~TestObject() called\n", this);
++destructors;
}
TestObject& TestObject::operator=(CONST TestObject& inObj)
{
//printf("%p -- operator= called\n", this);
_version = inObj._version;
return *this;
}
void testRoutine() {
TestObject one;
void (^b)(void) = ^{ printf("my const copy of one is %d\n", one.version()); };
}
int main(int argc, char *argv[]) {
testRoutine();
if (constructors == 0) {
printf("No copy constructors!!!\n");
return 1;
}
if (constructors != destructors) {
printf("%d constructors but only %d destructors\n", constructors, destructors);
return 1;
}
printf("%s:success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,37 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* copynull.c
* testObjects
*
* Created by Blaine Garst on 10/15/08.
*
*/
#import <stdio.h>
#import <Block.h>
#import <Block_private.h>
// CONFIG rdar://6295848
int main(int argc, char *argv[]) {
void (^block)(void) = (void (^)(void))0;
void (^blockcopy)(void) = Block_copy(block);
if (blockcopy != (void (^)(void))0) {
printf("whoops, somehow we copied NULL!\n");
return 1;
}
// make sure we can also
Block_release(blockcopy);
// and more secretly
//_Block_destroy(blockcopy);
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,57 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#include <CoreFoundation/CoreFoundation.h>
#include <dispatch/dispatch.h>
#include <unistd.h>
//#import <Foundation/Foundation.h>
#include <Block.h>
// CONFIG rdar://problem/6371811
const char *whoami = "nobody";
void EnqueueStuff(dispatch_queue_t q)
{
__block CFIndex counter;
// above call has a side effect: it works around:
// <rdar://problem/6225809> __block variables not implicitly imported into intermediate scopes
dispatch_async(q, ^{
counter = 0;
});
dispatch_async(q, ^{
//printf("outer block.\n");
counter++;
dispatch_async(q, ^{
//printf("inner block.\n");
counter--;
if(counter == 0) {
printf("%s: success\n", whoami);
exit(0);
}
});
if(counter == 0) {
printf("already done? inconceivable!\n");
exit(1);
}
});
}
int main (int argc, const char * argv[]) {
dispatch_queue_t q = dispatch_queue_create("queue", NULL);
whoami = argv[0];
EnqueueStuff(q);
dispatch_main();
printf("shouldn't get here\n");
return 1;
}

View File

@ -0,0 +1,31 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#include <stdio.h>
#include <Block.h>
// CONFIG
void callsomething(const char *format, int argument) {
}
void
dispatch_call_Block_with_release2(void *block)
{
void (^b)(void) = (void (^)(void))block;
b();
Block_release(b);
}
int main(int argc, char *argv[]) {
void (^b1)(void) = ^{ callsomething("argc is %d\n", argc); };
void (^b2)(void) = ^{ callsomething("hellow world\n", 0); }; // global block now
dispatch_call_Block_with_release2(Block_copy(b1));
dispatch_call_Block_with_release2(Block_copy(b2));
printf("%s: Success\n", argv[0]);
return 0;
}

107
BlocksRuntime/tests/fail.c Normal file
View File

@ -0,0 +1,107 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* fail.c
* testObjects
*
* Created by Blaine Garst on 9/16/08.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
bool readfile(char *buffer, const char *from) {
int fd = open(from, 0);
if (fd < 0) return false;
int count = read(fd, buffer, 512);
if (count < 0) return false;
buffer[count] = 0; // zap newline
return true;
}
// basic idea, take compiler args, run compiler, and verify that expected failure matches any existing one
int main(int argc, char *argv[]) {
if (argc == 1) return 0;
char *copy[argc+1]; // make a copy
// find and strip off -e "errorfile"
char *errorfile = NULL;
int counter = 0, i = 0;
for (i = 1; i < argc; ++i) { // skip 0 arg which is "fail"
if (!strncmp(argv[i], "-e", 2)) {
errorfile = argv[++i];
}
else {
copy[counter++] = argv[i];
}
}
copy[counter] = NULL;
pid_t child = fork();
char buffer[512];
if (child == 0) {
// in child
sprintf(buffer, "/tmp/errorfile_%d", getpid());
close(1);
int fd = creat(buffer, 0777);
if (fd != 1) {
fprintf(stderr, "didn't open custom error file %s as 1, got %d\n", buffer, fd);
exit(1);
}
close(2);
dup(1);
int result = execv(copy[0], copy);
exit(10);
}
if (child < 0) {
printf("fork failed\n");
exit(1);
}
int status = 0;
pid_t deadchild = wait(&status);
if (deadchild != child) {
printf("wait got %d instead of %d\n", deadchild, child);
exit(1);
}
if (WEXITSTATUS(status) == 0) {
printf("compiler exited normally, not good under these circumstances\n");
exit(1);
}
//printf("exit status of child %d was %d\n", child, WEXITSTATUS(status));
sprintf(buffer, "/tmp/errorfile_%d", child);
if (errorfile) {
//printf("ignoring error file: %s\n", errorfile);
char desired[512];
char got[512];
bool gotErrorFile = readfile(desired, errorfile);
bool gotOutput = readfile(got, buffer);
if (!gotErrorFile && gotOutput) {
printf("didn't read errorfile %s, it should have something from\n*****\n%s\n*****\nin it.\n",
errorfile, got);
exit(1);
}
else if (gotErrorFile && gotOutput) {
char *where = strstr(got, desired);
if (!where) {
printf("didn't find contents of %s in %s\n", errorfile, buffer);
exit(1);
}
}
else {
printf("errorfile %s and output %s inconsistent\n", errorfile, buffer);
exit(1);
}
}
unlink(buffer);
printf("success\n");
exit(0);
}

View File

@ -0,0 +1,21 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#include <stdio.h>
/* CONFIG rdar://6310599
*/
int main(int argc, char *argv[])
{
__block int flags;
__block void *isa;
^{ flags=1; isa = (void *)isa; };
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,42 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// testfilerunner CONFIG
#import <stdio.h>
#import <Block.h>
int global;
void (^gblock)(int) = ^(int x){ global = x; };
int main(int argc, char *argv[]) {
gblock(1);
if (global != 1) {
printf("%s: *** did not set global to 1\n", argv[0]);
return 1;
}
void (^gblockcopy)(int) = Block_copy(gblock);
if (gblockcopy != gblock) {
printf("global copy %p not a no-op %p\n", (void *)gblockcopy, (void *)gblock);
return 1;
}
Block_release(gblockcopy);
gblock(3);
if (global != 3) {
printf("%s: *** did not set global to 3\n", argv[0]);
return 1;
}
gblockcopy = Block_copy(gblock);
gblockcopy(5);
if (global != 5) {
printf("%s: *** did not set global to 5\n", argv[0]);
return 1;
}
printf("%s: Success!\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,34 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* goto.c
* testObjects
*
* Created by Blaine Garst on 10/17/08.
*
*/
// CONFIG rdar://6289031
#include <stdio.h>
int main(int argc, char *argv[])
{
__block int val = 0;
^{ val = 1; }();
if (val == 0) {
goto out_bad; // error: local byref variable val is in the scope of this goto
}
printf("%s: Success!\n", argv[0]);
return 0;
out_bad:
printf("%s: val not updated!\n", argv[0]);
return 1;
}

View File

@ -0,0 +1,29 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG C
#include <stdio.h>
#include <Block_private.h>
int main(int argc, char *argv[]) {
void (^inner)(void) = ^ { printf("argc was %d\n", argc); };
void (^outer)(void) = ^{
inner();
inner();
};
//printf("size of inner is %ld\n", Block_size(inner));
//printf("size of outer is %ld\n", Block_size(outer));
if (Block_size(inner) != Block_size(outer)) {
printf("not the same size, using old compiler??\n");
return 1;
}
printf("%s: Success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,32 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG C++ GC RR open rdar://6347910
struct MyStruct {
int something;
};
struct TestObject {
void test(void){
{
MyStruct first; // works
}
void (^b)(void) = ^{
MyStruct inner; // fails to compile!
};
}
};
int main(int argc, char *argv[]) {
printf("%s: Success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,33 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
// CONFIG error: incompatible block pointer types assigning
#import <stdio.h>
#import <stdlib.h>
int main(int argc, char *argv[]) {
#ifndef __cplusplus
char (^rot13)();
rot13 = ^(char c) { return (char)(((c - 'a' + 13) % 26) + 'a'); };
char n = rot13('a');
char c = rot13('p');
if ( n != 'n' || c != 'c' ) {
printf("%s: rot13('a') returned %c, rot13('p') returns %c\n", argv[0], n, c);
exit(1);
}
#else
// yield characteristic error message for C++
#error incompatible block pointer types assigning
#endif
#ifndef __clang__
// yield characteristic error message for C++
#error incompatible block pointer types assigning
#endif
printf("%s: success\n", argv[0]);
exit(0);
}

View File

@ -0,0 +1,51 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
// CONFIG
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
typedef struct {
unsigned long ps[30];
int qs[30];
} BobTheStruct;
int main (int argc, const char * argv[]) {
BobTheStruct inny;
BobTheStruct outty;
BobTheStruct (^copyStruct)(BobTheStruct);
int i;
memset(&inny, 0xA5, sizeof(inny));
memset(&outty, 0x2A, sizeof(outty));
for(i=0; i<30; i++) {
inny.ps[i] = i * i * i;
inny.qs[i] = -i * i * i;
}
copyStruct = ^(BobTheStruct aBigStruct){ return aBigStruct; }; // pass-by-value intrinsically copies the argument
outty = copyStruct(inny);
if ( &inny == &outty ) {
printf("%s: struct wasn't copied.", argv[0]);
exit(1);
}
for(i=0; i<30; i++) {
if ( (inny.ps[i] != outty.ps[i]) || (inny.qs[i] != outty.qs[i]) ) {
printf("%s: struct contents did not match.", argv[0]);
exit(1);
}
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,42 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* localisglobal.c
* testObjects
*
* Created by Blaine Garst on 9/29/08.
*
* works in all configurations
* CONFIG rdar://6230297
*/
#include <stdio.h>
void (^global)(void) = ^{ printf("hello world\n"); };
int aresame(void *first, void *second) {
long *f = (long *)first;
long *s = (long *)second;
return *f == *s;
}
int main(int argc, char *argv[]) {
int i = 10;
void (^local)(void) = ^ { printf("hi %d\n", i); };
void (^localisglobal)(void) = ^ { printf("hi\n"); };
if (aresame(local, localisglobal)) {
printf("local block could be global, but isn't\n");
return 1;
}
if (!aresame(global, localisglobal)) {
printf("local block is not global, not stack, what is it??\n");
return 1;
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,14 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG open rdar://6718399
#include <Block.h>
void foo() {
void (^bbb)(void) = Block_copy(^ {
int j, cnt;
});
}

View File

@ -0,0 +1,70 @@
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
CCDIR=/usr/bin
#CCDIR=/Volumes/Keep/gcc/usr/bin
all: std
clean:
rm -fr *.dSYM *.o *-bin testfilerunner
TFR = ~public/bin/testfilerunner
testfilerunner: testfilerunner.h testfilerunner.m
gcc -fobjc-gc-only -g -arch x86_64 -arch i386 -std=gnu99 testfilerunner.m -o testfilerunner -framework Foundation
tests:
grep CONFIG *.[cmCM] | $(TFR) $(CCDIR) --
open:
grep CONFIG *.[cmCM] | $(TFR) $(CCDIR) -open --
fast:
grep CONFIG *.[cmCM] | $(TFR) -fast $(CCDIR) --
std:
grep CONFIG *.[cmCM] | $(TFR) --
clang:
grep CONFIG *.[cmCM] | $(TFR) -clang -fast --
fastd:
grep CONFIG *.[cmCM] | $(TFR) -fast --
# Hack Alert: arguably most of the following belongs in libclosure's Makefile; sticking it here until I get around to grokking what goes on in that file.
sudid:
@echo Enabling sudo: # Hack Alert: enable sudo first thing so we don't hang at the password prompt later
@sudo echo Thanks
RootsDirectory ?= /tmp/
# Note: the libsystem project (built by the libsystemroot target below) uses the ALTUSRLOCALLIBSYSTEM variable, so we use it here to maintain parity
ALTUSRLOCALLIBSYSTEM ?= $(RootsDirectory)/alt-usr-local-lib-system/
altusrlocallibsystem:
ditto /usr/local/lib/system $(ALTUSRLOCALLIBSYSTEM) # FIXME: conditionalize this copy
# <rdar://problem/6456031> ER: option to not require extra privileges (-nosudo or somesuch)
Buildit ?= ~rc/bin/buildit -rootsDirectory $(RootsDirectory) -arch i386 -arch ppc -arch x86_64
blocksroot: sudid clean altusrlocallibsystem
sudo $(Buildit) ..
ditto $(RootsDirectory)/libclosure.roots/libclosure~dst/usr/local/lib/system $(ALTUSRLOCALLIBSYSTEM)
LibsystemVersion ?= 121
LibsystemPath ?= ~rc/Software/SnowLeopard/Projects/Libsystem/Libsystem-$(LibsystemVersion)
LibsystemTmpPath ?= $(RootsDirectory)/Libsystem-$(LibsystemVersion)
libsystemroot: blocksroot
ditto $(LibsystemPath) $(LibsystemTmpPath) # FIXME: conditionalize this copy
sudo ALTUSRLOCALLIBSYSTEM=$(ALTUSRLOCALLIBSYSTEM) $(Buildit) $(LibsystemTmpPath)
# Defaults to product of the libsystemroot target but does not automatically rebuild that, make both targets if you want a fresh root
LibsystemRootPath ?= $(RootsDirectory)/Libsystem-$(LibsystemVersion).roots/Libsystem-$(LibsystemVersion)~dst/usr/lib/
roottests:
grep CONFIG *.[cmCM] | $(TFR) -dyld $(LibsystemRootPath) -- # FIXME: figure out if I can "call" the std target instead of duplicating it

View File

@ -0,0 +1,18 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#include <stdio.h>
// CONFIG
int AGlobal;
int main(int argc, char *argv[]) {
void (^f)(void) = ^ { AGlobal++; };
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,44 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// nestedimport.m
// testObjects
//
// Created by Blaine Garst on 6/24/08.
//
// pure C nothing more needed
// CONFIG
#include <stdio.h>
#include <stdlib.h>
int Global = 0;
void callVoidVoid(void (^closure)(void)) {
closure();
}
int main(int argc, char *argv[]) {
int i = 1;
void (^vv)(void) = ^{
if (argc > 0) {
callVoidVoid(^{ Global = i; });
}
};
i = 2;
vv();
if (Global != 1) {
printf("%s: error, Global not set to captured value\n", argv[0]);
exit(1);
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,43 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// nullblockisa.m
// testObjects
//
// Created by Blaine Garst on 9/24/08.
//
// CONFIG rdar://6244520
#include <stdio.h>
#include <stdlib.h>
#include <Block_private.h>
void check(void (^b)(void)) {
struct _custom {
struct Block_layout layout;
struct Block_byref *innerp;
} *custom = (struct _custom *)(void *)(b);
//printf("block is at %p, size is %lx, inner is %p\n", (void *)b, Block_size(b), innerp);
if (custom->innerp->isa != (void *)NULL) {
printf("not a NULL __block isa\n");
exit(1);
}
return;
}
int main(int argc, char *argv[]) {
__block int i;
check(^{ printf("%d\n", ++i); });
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,77 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* objectRRGC.c
* testObjects
*
* Created by Blaine Garst on 10/31/08.
*
* Test that the runtime honors the new callouts properly for retain/release and GC
* CON FIG C rdar://6175959
*/
#include <stdio.h>
#include <Block_private.h>
int AssignCalled = 0;
int DisposeCalled = 0;
// local copy instead of libSystem.B.dylib copy
void _Block_object_assign(void *destAddr, const void *object, const int isWeak) {
//printf("_Block_object_assign(%p, %p, %d) called\n", destAddr, object, isWeak);
AssignCalled = 1;
}
void _Block_object_dispose(const void *object, const int isWeak) {
//printf("_Block_object_dispose(%p, %d) called\n", object, isWeak);
DisposeCalled = 1;
}
struct MyStruct {
long isa;
long field;
};
typedef struct MyStruct *__attribute__((NSObject)) MyStruct_t;
int main(int argc, char *argv[]) {
// create a block
struct MyStruct X;
MyStruct_t xp = (MyStruct_t)&X;
xp->field = 10;
void (^myBlock)(void) = ^{ printf("field is %ld\n", xp->field); };
// should be a copy helper generated with a calls to above routines
// Lets find out!
struct Block_layout *bl = (struct Block_layout *)(void *)myBlock;
if ((bl->flags & BLOCK_HAS_DESCRIPTOR) != BLOCK_HAS_DESCRIPTOR) {
printf("using old runtime layout!\n");
return 1;
}
if ((bl->flags & BLOCK_HAS_COPY_DISPOSE) != BLOCK_HAS_COPY_DISPOSE) {
printf("no copy dispose!!!!\n");
return 1;
}
// call helper routines directly. These will, in turn, we hope, call the stubs above
long destBuffer[256];
//printf("destbuffer is at %p, block at %p\n", destBuffer, (void *)bl);
//printf("dump is %s\n", _Block_dump(myBlock));
bl->descriptor->copy(destBuffer, bl);
bl->descriptor->dispose(bl);
if (AssignCalled == 0) {
printf("did not call assign helper!\n");
return 1;
}
if (DisposeCalled == 0) {
printf("did not call dispose helper\n");
return 1;
}
printf("%s: Success!\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,76 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* objectassign.c
* testObjects
*
* Created by Blaine Garst on 10/28/08.
*
* This just tests that the compiler is issuing the proper helper routines
* CONFIG C rdar://6175959
*/
#include <stdio.h>
#include <Block_private.h>
int AssignCalled = 0;
int DisposeCalled = 0;
// local copy instead of libSystem.B.dylib copy
void _Block_object_assign(void *destAddr, const void *object, const int isWeak) {
//printf("_Block_object_assign(%p, %p, %d) called\n", destAddr, object, isWeak);
AssignCalled = 1;
}
void _Block_object_dispose(const void *object, const int isWeak) {
//printf("_Block_object_dispose(%p, %d) called\n", object, isWeak);
DisposeCalled = 1;
}
struct MyStruct {
long isa;
long field;
};
typedef struct MyStruct *__attribute__((NSObject)) MyStruct_t;
int main(int argc, char *argv[]) {
if (__APPLE_CC__ < 5627) {
printf("need compiler version %d, have %d\n", 5627, __APPLE_CC__);
return 0;
}
// create a block
struct MyStruct X;
MyStruct_t xp = (MyStruct_t)&X;
xp->field = 10;
void (^myBlock)(void) = ^{ printf("field is %ld\n", xp->field); };
// should be a copy helper generated with a calls to above routines
// Lets find out!
struct Block_layout *bl = (struct Block_layout *)(void *)myBlock;
if ((bl->flags & BLOCK_HAS_COPY_DISPOSE) != BLOCK_HAS_COPY_DISPOSE) {
printf("no copy dispose!!!!\n");
return 1;
}
// call helper routines directly. These will, in turn, we hope, call the stubs above
long destBuffer[256];
//printf("destbuffer is at %p, block at %p\n", destBuffer, (void *)bl);
//printf("dump is %s\n", _Block_dump(myBlock));
bl->descriptor->copy(destBuffer, bl);
bl->descriptor->dispose(bl);
if (AssignCalled == 0) {
printf("did not call assign helper!\n");
return 1;
}
if (DisposeCalled == 0) {
printf("did not call dispose helper\n");
return 1;
}
printf("%s: Success!\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,23 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* orbars.c
* testObjects
*
* Created by Blaine Garst on 9/17/08.
*
* CONFIG rdar://6276695 error: before | token
*/
#include <stdio.h>
int main(int argc, char *argv[]) {
int i = 10;
void (^b)(void) = ^(void){ | i | printf("hello world, %d\n", ++i); };
printf("%s: success :-(\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,32 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG rdar://6396238
#include <stdio.h>
#include <stdlib.h>
static int count = 0;
void (^mkblock(void))(void)
{
count++;
return ^{
count++;
};
}
int main (int argc, const char * argv[]) {
mkblock()();
if (count != 2) {
printf("%s: failure, 2 != %d\n", argv[0], count);
exit(1);
} else {
printf("%s: success\n", argv[0]);
exit(0);
}
return 0;
}

View File

@ -0,0 +1,29 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG rdar://6405500
#include <stdio.h>
#include <stdlib.h>
#import <dispatch/dispatch.h>
#import <objc/objc-auto.h>
int main (int argc, const char * argv[]) {
__block void (^blockFu)(size_t t);
blockFu = ^(size_t t){
if (t == 20) {
printf("%s: success\n", argv[0]);
exit(0);
} else
dispatch_async(dispatch_get_main_queue(), ^{ blockFu(20); });
};
dispatch_apply(10, dispatch_get_concurrent_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT), blockFu);
dispatch_main();
printf("shouldn't get here\n");
return 1;
}

View File

@ -0,0 +1,31 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG rdar://6414583
// a smaller case of byrefcopyint
#include <Block.h>
#include <dispatch/dispatch.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
__block int c = 1;
//printf("&c = %p - c = %i\n", &c, c);
int i;
for(i =0; i < 2; i++) {
dispatch_block_t block = Block_copy(^{ c = i; });
block();
// printf("%i: &c = %p - c = %i\n", i, &c, c);
Block_release(block);
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,55 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#include <stdio.h>
#include <Block.h>
#include <Block_private.h>
#include <stdlib.h>
// CONFIG
int cumulation = 0;
int doSomething(int i) {
cumulation += i;
return cumulation;
}
void dirtyStack() {
int i = random();
int j = doSomething(i);
int k = doSomething(j);
doSomething(i + j + k);
}
typedef void (^voidVoid)(void);
voidVoid testFunction() {
int i = random();
__block voidVoid inner = ^{ doSomething(i); };
//printf("inner, on stack, is %p\n", (void*)inner);
/*__block*/ voidVoid outer = ^{
//printf("will call inner block %p\n", (void *)inner);
inner();
};
//printf("outer looks like: %s\n", _Block_dump(outer));
voidVoid result = Block_copy(outer);
//Block_release(inner);
return result;
}
int main(int argc, char **argv) {
voidVoid block = testFunction();
dirtyStack();
block();
Block_release(block);
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,74 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG open rdar://6416474
// was rdar://5847976
// was rdar://6348320
#include <stdio.h>
#include <Block.h>
int verbose = 0;
int main(int argc, char* argv[]) {
if (argc > 1) verbose = 1;
__block void (^recursive_local_block)(int);
if (verbose) printf("recursive_local_block is a local recursive block\n");
recursive_local_block = ^(int i) {
if (verbose) printf("%d\n", i);
if (i > 0) {
recursive_local_block(i - 1);
}
};
if (verbose) printf("recursive_local_block's address is %p, running it:\n", (void*)recursive_local_block);
recursive_local_block(5);
if (verbose) printf("Creating other_local_block: a local block that calls recursive_local_block\n");
void (^other_local_block)(int) = ^(int i) {
if (verbose) printf("other_local_block running\n");
recursive_local_block(i);
};
if (verbose) printf("other_local_block's address is %p, running it:\n", (void*)other_local_block);
other_local_block(5);
#if __APPLE_CC__ >= 5627
if (verbose) printf("Creating other_copied_block: a Block_copy of a block that will call recursive_local_block\n");
void (^other_copied_block)(int) = Block_copy(^(int i) {
if (verbose) printf("other_copied_block running\n");
recursive_local_block(i);
});
if (verbose) printf("other_copied_block's address is %p, running it:\n", (void*)other_copied_block);
other_copied_block(5);
#endif
__block void (^recursive_copy_block)(int);
if (verbose) printf("Creating recursive_copy_block: a Block_copy of a block that will call recursive_copy_block recursively\n");
recursive_copy_block = Block_copy(^(int i) {
if (verbose) printf("%d\n", i);
if (i > 0) {
recursive_copy_block(i - 1);
}
});
if (verbose) printf("recursive_copy_block's address is %p, running it:\n", (void*)recursive_copy_block);
recursive_copy_block(5);
printf("%s: Success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,44 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* recursiveassign.c
* testObjects
*
* Created by Blaine Garst on 12/3/08.
*
*/
// CONFIG rdar://6639533
// The compiler is prefetching x->forwarding before evaluting code that recomputes forwarding and so the value goes to a place that is never seen again.
#include <stdio.h>
#include <stdlib.h>
#include <Block.h>
int main(int argc, char* argv[]) {
__block void (^recursive_copy_block)(int) = ^(int arg) { printf("got wrong Block\n"); exit(1); };
recursive_copy_block = Block_copy(^(int i) {
if (i > 0) {
recursive_copy_block(i - 1);
}
else {
printf("done!\n");
}
});
recursive_copy_block(5);
printf("%s: Success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,95 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
#import <Block.h>
#import <stdio.h>
#import <stdlib.h>
// CONFIG C++
int recovered = 0;
int constructors = 0;
int destructors = 0;
#define CONST const
class TestObject
{
public:
TestObject(CONST TestObject& inObj);
TestObject();
~TestObject();
TestObject& operator=(CONST TestObject& inObj);
void test(void);
int version() CONST { return _version; }
private:
mutable int _version;
};
TestObject::TestObject(CONST TestObject& inObj)
{
++constructors;
_version = inObj._version;
//printf("%p (%d) -- TestObject(const TestObject&) called", this, _version);
}
TestObject::TestObject()
{
_version = ++constructors;
//printf("%p (%d) -- TestObject() called\n", this, _version);
}
TestObject::~TestObject()
{
//printf("%p -- ~TestObject() called\n", this);
++destructors;
}
#if 1
TestObject& TestObject::operator=(CONST TestObject& inObj)
{
//printf("%p -- operator= called", this);
_version = inObj._version;
return *this;
}
#endif
void TestObject::test(void) {
void (^b)(void) = ^{ recovered = _version; };
void (^b2)(void) = Block_copy(b);
b2();
Block_release(b2);
}
void testRoutine() {
TestObject one;
one.test();
}
int main(int argc, char *argv[]) {
testRoutine();
if (recovered == 1) {
printf("%s: success\n", argv[0]);
exit(0);
}
printf("%s: *** didn't recover byref block variable\n", argv[0]);
exit(1);
}

View File

@ -0,0 +1,36 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* rettypepromotion.c
* testObjects
*
* Created by Blaine Garst on 11/3/08.
*
*/
// CONFIG error:
// C++ and C give different errors so we don't check for an exact match.
// The error is that enum's are defined to be ints, always, even if defined with explicit long values
#include <stdio.h>
#include <stdlib.h>
enum { LESS = -1, EQUAL, GREATER };
void sortWithBlock(long (^comp)(void *arg1, void *arg2)) {
}
int main(int argc, char *argv[]) {
sortWithBlock(^(void *arg1, void *arg2) {
if (random()) return LESS;
if (random()) return EQUAL;
if (random()) return GREATER;
});
printf("%s: Success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,23 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// CONFIG rdar://6339747 but wasn't
#include <stdio.h>
int (*funcptr)(long);
int (*(^b)(char))(long);
int main(int argc, char *argv[]) {
// implicit is fine
b = ^(char x) { return funcptr; };
// explicit never parses
b = ^int (*(char x))(long) { return funcptr; };
printf("%s: Success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,24 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* shorthandexpression.c
* testObjects
*
* Created by Blaine Garst on 9/16/08.
*
* CONFIG error:
*/
void foo() {
void (^b)(void) = ^(void)printf("hello world\n");
}
int main(int argc, char *argv[]) {
printf("%s: this shouldn't compile\n", argv[0]);
return 1;
}

View File

@ -0,0 +1,26 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* sizeof.c
* testObjects
*
* Created by Blaine Garst on 2/17/09.
*
*/
#include <stdio.h>
// CONFIG error:
int main(int argc, char *argv[]) {
void (^aBlock)(void) = ^{ printf("hellow world\n"); };
printf("the size of a block is %ld\n", sizeof(*aBlock));
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,45 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
// CONFIG
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
typedef struct {
int a;
int b;
} MiniStruct;
int main (int argc, const char * argv[]) {
MiniStruct inny;
MiniStruct outty;
MiniStruct (^copyStruct)(MiniStruct);
memset(&inny, 0xA5, sizeof(inny));
memset(&outty, 0x2A, sizeof(outty));
inny.a = 12;
inny.b = 42;
copyStruct = ^(MiniStruct aTinyStruct){ return aTinyStruct; }; // pass-by-value intrinsically copies the argument
outty = copyStruct(inny);
if ( &inny == &outty ) {
printf("%s: struct wasn't copied.", argv[0]);
exit(1);
}
if ( (inny.a != outty.a) || (inny.b != outty.b) ) {
printf("%s: struct contents did not match.", argv[0]);
exit(1);
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,45 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* structmember.c
* testObjects
*
* Created by Blaine Garst on 9/30/08.
* CONFIG
*/
#include <Block.h>
#include <Block_private.h>
#include <stdio.h>
// CONFIG
int main(int argc, char *argv[]) {
struct stuff {
long int a;
long int b;
long int c;
} localStuff = { 10, 20, 30 };
int d;
void (^a)(void) = ^ { printf("d is %d", d); };
void (^b)(void) = ^ { printf("d is %d, localStuff.a is %lu", d, localStuff.a); };
unsigned nominalsize = Block_size(b) - Block_size(a);
#if __cplusplus__
// need copy+dispose helper for C++ structures
nominalsize += 2*sizeof(void*);
#endif
if ((Block_size(b) - Block_size(a)) != nominalsize) {
printf("sizeof a is %ld, sizeof b is %ld, expected %d\n", Block_size(a), Block_size(b), nominalsize);
printf("dump of b is %s\n", _Block_dump(b));
return 1;
}
printf("%s: Success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,110 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// testfilerunner.h
// testObjects
//
// Created by Blaine Garst on 9/24/08.
//
#import <Cocoa/Cocoa.h>
/*
variations:
four source types: C, ObjC, C++, ObjC++,
and for ObjC or ObjC++ we have
RR and GC capabilities
we assume C++ friendly includes for C/ObjC even if C++ isn't used
four compilers: C, ObjC, C++, ObjC++
and for ObjC or ObjC++ we can compile
RR, RR+GC, GC+RR, GC
although to test RR+GC we need to build a shell "main" in both modes
and/or run with GC disabled if possible.
To maximize coverage we mark files with capabilities and then ask them to be
compiled with each variation of compiler and option.
If the file doesn't have the capability it politely refuses.
*/
enum options {
Do64 = (1 << 0),
DoCPP = (1 << 1),
DoOBJC = (1 << 3),
DoGC = (1 << 4),
DoRR = (1 << 5),
DoRRGC = (1 << 6), // -fobjc-gc but main w/o so it runs in RR mode
DoGCRR = (1 << 7), // -fobjc-gc & run GC mode
//DoDashG = (1 << 8),
DoDashO = (1 << 9),
DoDashOs = (1 << 10),
DoDashO2 = (1 << 11),
DoC99 = (1 << 12), // -std=c99
};
@class TestFileExeGenerator;
// this class will actually compile and/or run a target binary
// XXX we don't track which dynamic libraries requested/used nor set them up
@interface TestFileExe : NSObject {
NSPointerArray *compileLine;
int options;
bool shouldFail;
TestFileExeGenerator *generator;
__strong char *binaryName;
__strong char *sourceName;
__strong char *libraryPath;
__strong char *frameworkPath;
}
@property int options;
@property(assign) NSPointerArray *compileLine;
@property(assign) TestFileExeGenerator *generator;
@property bool shouldFail;
@property __strong char *binaryName;
@property __strong char *sourceName;
@property __strong char *libraryPath;
@property __strong char *frameworkPath;
- (bool) compileUnlessExists:(bool)skip;
- (bool) run;
@property(readonly) __strong char *radar;
@end
// this class generates an appropriate set of configurations to compile
// we don't track which gcc we use but we should XXX
@interface TestFileExeGenerator : NSObject {
bool hasObjC;
bool hasRR;
bool hasGC;
bool hasCPlusPlus;
bool wantsC99;
bool wants64;
bool wants32;
bool supposedToNotCompile;
bool open; // this problem is still open - e.g. unresolved
__strong char *radar; // for things already known to go wrong
__strong char *filename;
__strong char *compilerPath;
__strong char *errorString;
__strong char *warningString;
NSPointerArray *extraLibraries;
}
@property bool hasObjC, hasRR, hasGC, hasCPlusPlus, wantsC99, supposedToNotCompile, open, wants32, wants64;
@property(assign) __strong char *radar;
@property __strong char *filename;
@property __strong char *compilerPath;
@property __strong char *errorString;
@property __strong char *warningString;
- (TestFileExe *)lineForOptions:(int)options; // nil if no can do
+ (NSArray *)generatorsFromFILE:(FILE *)fd;
+ (NSArray *)generatorsFromPath:(NSString *)path;
@end

View File

@ -0,0 +1,805 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
// testfilerunner.m
// testObjects
//
// Created by Blaine Garst on 9/24/08.
//
#import "testfilerunner.h"
#import <Foundation/Foundation.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
bool Everything = false; // do it also with 3 levels of optimization
bool DoClang = false;
static bool isDirectory(char *path);
static bool isExecutable(char *path);
static bool isYounger(char *source, char *binary);
static bool readErrorFile(char *buffer, const char *from);
__strong char *gcstrcpy2(__strong const char *arg, char *endp) {
unsigned size = endp - arg + 1;
__strong char *result = NSAllocateCollectable(size, 0);
strncpy(result, arg, size);
result[size-1] = 0;
return result;
}
__strong char *gcstrcpy1(__strong char *arg) {
unsigned size = strlen(arg) + 1;
__strong char *result = NSAllocateCollectable(size, 0);
strncpy(result, arg, size);
result[size-1] = 0;
return result;
}
@implementation TestFileExe
@synthesize options, compileLine, shouldFail, binaryName, sourceName;
@synthesize generator;
@synthesize libraryPath, frameworkPath;
- (NSString *)description {
NSMutableString *result = [NSMutableString new];
if (shouldFail) [result appendString:@"fail"];
for (id x in compileLine) {
[result appendString:[NSString stringWithFormat:@" %s", (char *)x]];
}
return result;
}
- (__strong char *)radar {
return generator.radar;
}
- (bool) compileUnlessExists:(bool)skip {
if (shouldFail) {
printf("don't use this to compile anymore!\n");
return false;
}
if (skip && isExecutable(binaryName) && !isYounger(sourceName, binaryName)) return true;
int argc = [compileLine count];
char *argv[argc+1];
for (int i = 0; i < argc; ++i)
argv[i] = (char *)[compileLine pointerAtIndex:i];
argv[argc] = NULL;
pid_t child = fork();
if (child == 0) {
execv(argv[0], argv);
exit(10); // shouldn't happen
}
if (child < 0) {
printf("fork failed\n");
return false;
}
int status = 0;
pid_t deadchild = wait(&status);
if (deadchild != child) {
printf("wait got %d instead of %d\n", deadchild, child);
exit(1);
}
if (WEXITSTATUS(status) == 0) {
return true;
}
printf("run failed\n");
return false;
}
bool lookforIn(char *lookfor, const char *format, pid_t child) {
char buffer[512];
char got[512];
sprintf(buffer, format, child);
bool gotOutput = readErrorFile(got, buffer);
if (!gotOutput) {
printf("**** didn't get an output file %s to analyze!!??\n", buffer);
return false;
}
char *where = strstr(got, lookfor);
if (!where) {
printf("didn't find '%s' in output file %s\n", lookfor, buffer);
return false;
}
unlink(buffer);
return true;
}
- (bool) compileWithExpectedFailure {
if (!shouldFail) {
printf("Why am I being called?\n");
return false;
}
int argc = [compileLine count];
char *argv[argc+1];
for (int i = 0; i < argc; ++i)
argv[i] = (char *)[compileLine pointerAtIndex:i];
argv[argc] = NULL;
pid_t child = fork();
char buffer[512];
if (child == 0) {
// in child
sprintf(buffer, "/tmp/errorfile_%d", getpid());
close(1);
int fd = creat(buffer, 0777);
if (fd != 1) {
fprintf(stderr, "didn't open custom error file %s as 1, got %d\n", buffer, fd);
exit(1);
}
close(2);
dup(1);
int result = execv(argv[0], argv);
exit(10);
}
if (child < 0) {
printf("fork failed\n");
return false;
}
int status = 0;
pid_t deadchild = wait(&status);
if (deadchild != child) {
printf("wait got %d instead of %d\n", deadchild, child);
exit(11);
}
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) == 0) {
return false;
}
}
else {
printf("***** compiler borked/ICEd/died unexpectedly (status %x)\n", status);
return false;
}
char *error = generator.errorString;
if (!error) return true;
#if 0
char got[512];
sprintf(buffer, "/tmp/errorfile_%d", child);
bool gotOutput = readErrorFile(got, buffer);
if (!gotOutput) {
printf("**** didn't get an error file %s to analyze!!??\n", buffer);
return false;
}
char *where = strstr(got, error);
if (!where) {
printf("didn't find '%s' in error file %s\n", error, buffer);
return false;
}
unlink(buffer);
#else
if (!lookforIn(error, "/tmp/errorfile_%d", child)) return false;
#endif
return true;
}
- (bool) run {
if (shouldFail) return true;
if (sizeof(long) == 4 && options & Do64) {
return true; // skip 64-bit tests
}
int argc = 1;
char *argv[argc+1];
argv[0] = binaryName;
argv[argc] = NULL;
pid_t child = fork();
if (child == 0) {
// set up environment
char lpath[1024];
char fpath[1024];
char *myenv[3];
int counter = 0;
if (libraryPath) {
sprintf(lpath, "DYLD_LIBRARY_PATH=%s", libraryPath);
myenv[counter++] = lpath;
}
if (frameworkPath) {
sprintf(fpath, "DYLD_FRAMEWORK_PATH=%s", frameworkPath);
myenv[counter++] = fpath;
}
myenv[counter] = NULL;
if (generator.warningString) {
// set up stdout/stderr
char outfile[1024];
sprintf(outfile, "/tmp/stdout_%d", getpid());
close(2);
close(1);
creat(outfile, 0700);
dup(1);
}
execve(argv[0], argv, myenv);
exit(10); // shouldn't happen
}
if (child < 0) {
printf("fork failed\n");
return false;
}
int status = 0;
pid_t deadchild = wait(&status);
if (deadchild != child) {
printf("wait got %d instead of %d\n", deadchild, child);
exit(1);
}
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
if (generator.warningString) {
if (!lookforIn(generator.warningString, "/tmp/stdout_%d", child)) return false;
}
return true;
}
printf("**** run failed for %s\n", binaryName);
return false;
}
@end
@implementation TestFileExeGenerator
@synthesize filename, compilerPath, errorString;
@synthesize hasObjC, hasRR, hasGC, hasCPlusPlus, wantsC99, supposedToNotCompile, open, wants32, wants64;
@synthesize radar;
@synthesize warningString;
- (void)setFilename:(__strong char *)name {
filename = gcstrcpy1(name);
}
- (void)setCompilerPath:(__strong char *)name {
compilerPath = gcstrcpy1(name);
}
- (void)forMostThings:(NSMutableArray *)lines options:(int)options {
TestFileExe *item = nil;
item = [self lineForOptions:options];
if (item) [lines addObject:item];
item = [self lineForOptions:options|Do64];
if (item) [lines addObject:item];
item = [self lineForOptions:options|DoCPP];
if (item) [lines addObject:item];
item = [self lineForOptions:options|Do64|DoCPP];
if (item) [lines addObject:item];
}
/*
DoDashG = (1 << 8),
DoDashO = (1 << 9),
DoDashOs = (1 << 10),
DoDashO2 = (1 << 11),
*/
- (void)forAllThings:(NSMutableArray *)lines options:(int)options {
[self forMostThings:lines options:options];
if (!Everything) {
return;
}
// now do it with three explicit optimization flags
[self forMostThings:lines options:options | DoDashO];
[self forMostThings:lines options:options | DoDashOs];
[self forMostThings:lines options:options | DoDashO2];
}
- (NSArray *)allLines {
NSMutableArray *result = [NSMutableArray new];
TestFileExe *item = nil;
int options = 0;
[self forAllThings:result options:0];
[self forAllThings:result options:DoOBJC | DoRR];
[self forAllThings:result options:DoOBJC | DoGC];
[self forAllThings:result options:DoOBJC | DoGCRR];
//[self forAllThings:result options:DoOBJC | DoRRGC];
return result;
}
- (void)addLibrary:(const char *)dashLSomething {
if (!extraLibraries) {
extraLibraries = [NSPointerArray pointerArrayWithOptions:
NSPointerFunctionsStrongMemory |
NSPointerFunctionsCStringPersonality];
}
[extraLibraries addPointer:(void *)dashLSomething];
}
- (TestFileExe *)lineForOptions:(int)options { // nil if no can do
if (hasObjC && !(options & DoOBJC)) return nil;
if (hasCPlusPlus && !(options & DoCPP)) return nil;
if (hasObjC) {
if (!hasGC && (options & (DoGC|DoGCRR))) return nil; // not smart enough
if (!hasRR && (options & (DoRR|DoRRGC))) return nil;
}
NSPointerArray *pa = [NSPointerArray pointerArrayWithOptions:
NSPointerFunctionsStrongMemory |
NSPointerFunctionsCStringPersonality];
// construct path
char path[512];
path[0] = 0;
if (!compilerPath) compilerPath = "/usr/bin";
if (compilerPath) {
strcat(path, compilerPath);
strcat(path, "/");
}
if (options & DoCPP) {
strcat(path, DoClang ? "clang++" : "g++-4.2");
}
else {
strcat(path, DoClang ? "clang" : "gcc-4.2");
}
[pa addPointer:gcstrcpy1(path)];
if (options & DoOBJC) {
if (options & DoCPP) {
[pa addPointer:"-ObjC++"];
}
else {
[pa addPointer:"-ObjC"];
}
}
[pa addPointer:"-g"];
if (options & DoDashO) [pa addPointer:"-O"];
else if (options & DoDashO2) [pa addPointer:"-O2"];
else if (options & DoDashOs) [pa addPointer:"-Os"];
if (wantsC99 && (! (options & DoCPP))) {
[pa addPointer:"-std=c99"];
[pa addPointer:"-fblocks"];
}
[pa addPointer:"-arch"];
[pa addPointer: (options & Do64) ? "x86_64" : "i386"];
if (options & DoOBJC) {
switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) {
case DoRR:
break;
case DoGC:
[pa addPointer:"-fobjc-gc-only"];
break;
case DoGCRR:
[pa addPointer:"-fobjc-gc"];
break;
case DoRRGC:
printf("DoRRGC unsupported right now\n");
[pa addPointer:"-c"];
return nil;
}
[pa addPointer:"-framework"];
[pa addPointer:"Foundation"];
}
[pa addPointer:gcstrcpy1(filename)];
[pa addPointer:"-o"];
path[0] = 0;
strcat(path, filename);
strcat(path, ".");
strcat(path, (options & Do64) ? "64" : "32");
if (options & DoOBJC) {
switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) {
case DoRR: strcat(path, "-rr"); break;
case DoGC: strcat(path, "-gconly"); break;
case DoGCRR: strcat(path, "-gcrr"); break;
case DoRRGC: strcat(path, "-rrgc"); break;
}
}
if (options & DoCPP) strcat(path, "++");
if (options & DoDashO) strcat(path, "-O");
else if (options & DoDashO2) strcat(path, "-O2");
else if (options & DoDashOs) strcat(path, "-Os");
if (wantsC99) strcat(path, "-C99");
strcat(path, DoClang ? "-clang" : "-gcc");
strcat(path, "-bin");
TestFileExe *result = [TestFileExe new];
result.binaryName = gcstrcpy1(path); // could snarf copy in pa
[pa addPointer:result.binaryName];
for (id cString in extraLibraries) {
[pa addPointer:cString];
}
result.sourceName = gcstrcpy1(filename); // could snarf copy in pa
result.compileLine = pa;
result.options = options;
result.shouldFail = supposedToNotCompile;
result.generator = self;
return result;
}
+ (NSArray *)generatorsFromPath:(NSString *)path {
FILE *fp = fopen([path fileSystemRepresentation], "r");
if (fp == NULL) return nil;
NSArray *result = [self generatorsFromFILE:fp];
fclose(fp);
return result;
}
#define LOOKFOR "CON" "FIG"
char *__strong parseRadar(char *line) {
line = strstr(line, "rdar:"); // returns beginning
char *endp = line + strlen("rdar:");
while (*endp && *endp != ' ' && *endp != '\n')
++endp;
return gcstrcpy2(line, endp);
}
- (void)parseLibraries:(const char *)line {
start:
line = strstr(line, "-l");
char *endp = (char *)line + 2;
while (*endp && *endp != ' ' && *endp != '\n')
++endp;
[self addLibrary:gcstrcpy2(line, endp)];
if (strstr(endp, "-l")) {
line = endp;
goto start;
}
}
+ (TestFileExeGenerator *)generatorFromLine:(char *)line filename:(char *)filename {
TestFileExeGenerator *item = [TestFileExeGenerator new];
item.filename = gcstrcpy1(filename);
if (strstr(line, "GC")) item.hasGC = true;
if (strstr(line, "RR")) item.hasRR = true;
if (strstr(line, "C++")) item.hasCPlusPlus = true;
if (strstr(line, "-C99")) {
item.wantsC99 = true;
}
if (strstr(line, "64")) item.wants64 = true;
if (strstr(line, "32")) item.wants32 = true;
if (strstr(line, "-l")) [item parseLibraries:line];
if (strstr(line, "open")) item.open = true;
if (strstr(line, "FAIL")) item.supposedToNotCompile = true; // old
// compile time error
if (strstr(line, "error:")) {
item.supposedToNotCompile = true;
// zap newline
char *error = strstr(line, "error:") + strlen("error:");
// make sure we have something before the newline
char *newline = strstr(error, "\n");
if (newline && ((newline-error) > 1)) {
*newline = 0;
item.errorString = gcstrcpy1(strstr(line, "error:") + strlen("error: "));
}
}
// run time warning
if (strstr(line, "runtime:")) {
// zap newline
char *error = strstr(line, "runtime:") + strlen("runtime:");
// make sure we have something before the newline
char *newline = strstr(error, "\n");
if (newline && ((newline-error) > 1)) {
*newline = 0;
item.warningString = gcstrcpy1(strstr(line, "runtime:") + strlen("runtime:"));
}
}
if (strstr(line, "rdar:")) item.radar = parseRadar(line);
if (item.hasGC || item.hasRR) item.hasObjC = true;
if (!item.wants32 && !item.wants64) { // give them both if they ask for neither
item.wants32 = item.wants64 = true;
}
return item;
}
+ (NSArray *)generatorsFromFILE:(FILE *)fp {
NSMutableArray *result = [NSMutableArray new];
// pretend this is a grep LOOKFOR *.[cmCM][cmCM] input
// look for
// filename: ... LOOKFOR [GC] [RR] [C++] [FAIL ...]
char buf[512];
while (fgets(buf, 512, fp)) {
char *config = strstr(buf, LOOKFOR);
if (!config) continue;
char *filename = buf;
char *end = strchr(buf, ':');
*end = 0;
[result addObject:[self generatorFromLine:config filename:filename]];
}
return result;
}
+ (TestFileExeGenerator *)generatorFromFilename:(char *)filename {
FILE *fp = fopen(filename, "r");
if (!fp) {
printf("didn't open %s!!\n", filename);
return nil;
}
char buf[512];
while (fgets(buf, 512, fp)) {
char *config = strstr(buf, LOOKFOR);
if (!config) continue;
fclose(fp);
return [self generatorFromLine:config filename:filename];
}
fclose(fp);
// guess from filename
char *ext = strrchr(filename, '.');
if (!ext) return nil;
TestFileExeGenerator *result = [TestFileExeGenerator new];
result.filename = gcstrcpy1(filename);
if (!strncmp(ext, ".m", 2)) {
result.hasObjC = true;
result.hasRR = true;
result.hasGC = true;
}
else if (!strcmp(ext, ".c")) {
;
}
else if (!strcmp(ext, ".M") || !strcmp(ext, ".mm")) {
result.hasObjC = true;
result.hasRR = true;
result.hasGC = true;
result.hasCPlusPlus = true;
}
else if (!strcmp(ext, ".cc")
|| !strcmp(ext, ".cp")
|| !strcmp(ext, ".cxx")
|| !strcmp(ext, ".cpp")
|| !strcmp(ext, ".CPP")
|| !strcmp(ext, ".c++")
|| !strcmp(ext, ".C")) {
result.hasCPlusPlus = true;
}
else {
printf("unknown extension, file %s ignored\n", filename);
result = nil;
}
return result;
}
- (NSString *)description {
return [NSString stringWithFormat:@"%s: %s%s%s%s%s%s",
filename,
LOOKFOR,
hasGC ? " GC" : "",
hasRR ? " RR" : "",
hasCPlusPlus ? " C++" : "",
wantsC99 ? "C99" : "",
supposedToNotCompile ? " FAIL" : ""];
}
@end
void printDetails(NSArray *failures, const char *whatAreThey) {
if ([failures count]) {
NSMutableString *output = [NSMutableString new];
printf("%s:\n", whatAreThey);
for (TestFileExe *line in failures) {
printf("%s", line.binaryName);
char *radar = line.generator.radar;
if (radar)
printf(" (due to %s?),", radar);
printf(" recompile via:\n%s\n\n", line.description.UTF8String);
}
printf("\n");
}
}
void help(const char *whoami) {
printf("Usage: %s [-fast] [-e] [-dyld librarypath] [gcc4.2dir] [-- | source1 ...]\n", whoami);
printf(" -fast don't recompile if binary younger than source\n");
printf(" -open only run tests that are thought to still be unresolved\n");
printf(" -clang use the clang and clang++ compilers\n");
printf(" -e compile all variations also with -Os, -O2, -O3\n");
printf(" -dyld p override DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH to p when running tests\n");
printf(" <compilerpath> directory containing gcc-4.2 (or clang) that you wish to use to compile the tests\n");
printf(" -- assume stdin is a grep CON" "FIG across the test sources\n");
printf(" otherwise treat each remaining argument as a single test file source\n");
printf("%s will compile and run individual test files under a variety of compilers, c, obj-c, c++, and objc++\n", whoami);
printf(" .c files are compiled with all four compilers\n");
printf(" .m files are compiled with objc and objc++ compilers\n");
printf(" .C files are compiled with c++ and objc++ compilers\n");
printf(" .M files are compiled only with the objc++ compiler\n");
printf("(actually all forms of extensions recognized by the compilers are honored, .cc, .c++ etc.)\n");
printf("\nTest files should run to completion with no output and exit (return) 0 on success.\n");
printf("Further they should be able to be compiled and run with GC on or off and by the C++ compilers\n");
printf("A line containing the string CON" "FIG within the source enables restrictions to the above assumptions\n");
printf("and other options.\n");
printf("Following CON" "FIG the string\n");
printf(" C++ restricts the test to only be run by c++ and objc++ compilers\n");
printf(" GC restricts the test to only be compiled and run with GC on\n");
printf(" RR (retain/release) restricts the test to only be compiled and run with GC off\n");
printf("Additionally,\n");
printf(" -C99 restricts the C versions of the test to -fstd=c99 -fblocks\n");
printf(" -O adds the -O optimization level\n");
printf(" -O2 adds the -O2 optimization level\n");
printf(" -Os adds the -Os optimization level\n");
printf("Files that are known to exhibit unresolved problems can provide the term \"open\" and this can");
printf("in turn allow highlighting of fixes that have regressed as well as identify that fixes are now available.\n");
printf("Files that exhibit known bugs may provide\n");
printf(" rdar://whatever such that if they fail the rdar will get cited\n");
printf("Files that are expected to fail to compile should provide, as their last token sequence,\n");
printf(" error:\n");
printf(" or error: substring to match.\n");
printf("Files that are expected to produce a runtime error message should provide, as their last token sequence,\n");
printf(" warning: string to match\n");
printf("\n%s will compile and run all configurations of the test files and report a summary at the end. Good luck.\n", whoami);
printf(" Blaine Garst blaine@apple.com\n");
}
int main(int argc, char *argv[]) {
printf("running on %s-bit architecture\n", sizeof(long) == 4 ? "32" : "64");
char *compilerDir = "/usr/bin";
NSMutableArray *generators = [NSMutableArray new];
bool doFast = false;
bool doStdin = false;
bool onlyOpen = false;
char *libraryPath = getenv("DYLD_LIBRARY_PATH");
char *frameworkPath = getenv("DYLD_FRAMEWORK_PATH");
// process options
while (argc > 1) {
if (!strcmp(argv[1], "-fast")) {
doFast = true;
--argc;
++argv;
}
else if (!strcmp(argv[1], "-dyld")) {
doFast = true;
--argc;
++argv;
frameworkPath = argv[1];
libraryPath = argv[1];
--argc;
++argv;
}
else if (!strcmp(argv[1], "-open")) {
onlyOpen = true;
--argc;
++argv;
}
else if (!strcmp(argv[1], "-clang")) {
DoClang = true;
--argc;
++argv;
}
else if (!strcmp(argv[1], "-e")) {
Everything = true;
--argc;
++argv;
}
else if (!strcmp(argv[1], "--")) {
doStdin = true;
--argc;
++argv;
}
else if (!strcmp(argv[1], "-")) {
help(argv[0]);
return 1;
}
else if (argc > 1 && isDirectory(argv[1])) {
compilerDir = argv[1];
++argv;
--argc;
}
else
break;
}
// process remaining arguments, or stdin
if (argc == 1) {
if (doStdin)
generators = (NSMutableArray *)[TestFileExeGenerator generatorsFromFILE:stdin];
else {
help(argv[0]);
return 1;
}
}
else while (argc > 1) {
TestFileExeGenerator *generator = [TestFileExeGenerator generatorFromFilename:argv[1]];
if (generator) [generators addObject:generator];
++argv;
--argc;
}
// see if we can generate all possibilities
NSMutableArray *failureToCompile = [NSMutableArray new];
NSMutableArray *failureToFailToCompile = [NSMutableArray new];
NSMutableArray *failureToRun = [NSMutableArray new];
NSMutableArray *successes = [NSMutableArray new];
for (TestFileExeGenerator *generator in generators) {
//NSLog(@"got %@", generator);
if (onlyOpen && !generator.open) {
//printf("skipping resolved test %s\n", generator.filename);
continue; // skip closed if onlyOpen
}
if (!onlyOpen && generator.open) {
//printf("skipping open test %s\n", generator.filename);
continue; // skip open if not asked for onlyOpen
}
generator.compilerPath = compilerDir;
NSArray *tests = [generator allLines];
for (TestFileExe *line in tests) {
line.frameworkPath = frameworkPath; // tell generators about it instead XXX
line.libraryPath = libraryPath; // tell generators about it instead XXX
if ([line shouldFail]) {
if (doFast) continue; // don't recompile & don't count as success
if ([line compileWithExpectedFailure]) {
[successes addObject:line];
}
else
[failureToFailToCompile addObject:line];
}
else if ([line compileUnlessExists:doFast]) {
if ([line run]) {
printf("%s ran successfully\n", line.binaryName);
[successes addObject:line];
}
else {
[failureToRun addObject:line];
}
}
else {
[failureToCompile addObject:line];
}
}
}
printf("\n--- results ---\n\n%lu successes\n%lu unexpected compile failures\n%lu failure to fail to compile errors\n%lu run failures\n",
[successes count], [failureToCompile count], [failureToFailToCompile count], [failureToRun count]);
printDetails(failureToCompile, "unexpected compile failures");
printDetails(failureToFailToCompile, "should have failed to compile but didn't failures");
printDetails(failureToRun, "run failures");
if (onlyOpen && [successes count]) {
NSMutableSet *radars = [NSMutableSet new];
printf("The following tests ran successfully suggesting that they are now resolved:\n");
for (TestFileExe *line in successes) {
printf("%s\n", line.binaryName);
if (line.radar) [radars addObject:line.generator];
}
if ([radars count]) {
printf("The following radars may be resolved:\n");
for (TestFileExeGenerator *line in radars) {
printf("%s\n", line.radar);
}
}
}
return [failureToCompile count] + [failureToRun count];
}
#include <sys/stat.h>
static bool isDirectory(char *path) {
struct stat statb;
int retval = stat(path, &statb);
if (retval != 0) return false;
if (statb.st_mode & S_IFDIR) return true;
return false;
}
static bool isExecutable(char *path) {
struct stat statb;
int retval = stat(path, &statb);
if (retval != 0) return false;
if (!(statb.st_mode & S_IFREG)) return false;
if (statb.st_mode & S_IXUSR) return true;
return false;
}
static bool isYounger(char *source, char *binary) {
struct stat statb;
int retval = stat(binary, &statb);
if (retval != 0) return true; // if doesn't exit, lie
struct stat stata;
retval = stat(source, &stata);
if (retval != 0) return true; // we're hosed
// the greater the timeval the younger it is
if (stata.st_mtimespec.tv_sec > statb.st_mtimespec.tv_sec) return true;
if (stata.st_mtimespec.tv_nsec > statb.st_mtimespec.tv_nsec) return true;
return false;
}
static bool readErrorFile(char *buffer, const char *from) {
int fd = open(from, 0);
if (fd < 0) {
printf("didn't open %s, (might not have been created?)\n", buffer);
return false;
}
int count = read(fd, buffer, 512);
if (count < 1) {
printf("read error on %s\n", buffer);
return false;
}
buffer[count-1] = 0; // zap newline
return true;
}

View File

@ -0,0 +1,44 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
// HACK ALERT: gcc and g++ give different errors, referencing the line number to ensure that it checks for the right error; MUST KEEP IN SYNC WITH THE TEST
// CONFIG 27: error:
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <stdarg.h>
int main (int argc, const char * argv[]) {
int (^sumn)(int n, ...);
int six = 0;
sumn = ^(int a, int b, int n, ...){
int result = 0;
va_list numbers;
int i;
va_start(numbers, n);
for (i = 0 ; i < n ; i++) {
result += va_arg(numbers, int);
}
va_end(numbers);
return result;
};
six = sumn(3, 1, 2, 3);
if ( six != 6 ) {
printf("%s: Expected 6 but got %d\n", argv[0], six);
exit(1);
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,39 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// -*- mode:C; c-basic-offset:4; tab-width:4; intent-tabs-mode:nil; -*-
// CONFIG
#import <stdio.h>
#import <stdlib.h>
#import <string.h>
#import <stdarg.h>
int main (int argc, const char * argv[]) {
int (^sumn)(int n, ...) = ^(int n, ...){
int result = 0;
va_list numbers;
int i;
va_start(numbers, n);
for (i = 0 ; i < n ; i++) {
result += va_arg(numbers, int);
}
va_end(numbers);
return result;
};
int six = sumn(3, 1, 2, 3);
if ( six != 6 ) {
printf("%s: Expected 6 but got %d\n", argv[0], six);
exit(1);
}
printf("%s: success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,66 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* variadic.c
* testObjects
*
* Created by Blaine Garst on 2/17/09.
*
*/
// PURPOSE Test that variadic arguments compile and work for Blocks
// CONFIG
#include <stdarg.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
long (^addthem)(const char *, ...) = ^long (const char *format, ...){
va_list argp;
const char *p;
int i;
char c;
double d;
long result = 0;
va_start(argp, format);
//printf("starting...\n");
for (p = format; *p; p++) switch (*p) {
case 'i':
i = va_arg(argp, int);
//printf("i: %d\n", i);
result += i;
break;
case 'd':
d = va_arg(argp, double);
//printf("d: %g\n", d);
result += (int)d;
break;
case 'c':
c = va_arg(argp, int);
//printf("c: '%c'\n", c);
result += c;
break;
}
//printf("...done\n\n");
return result;
};
long testresult = addthem("ii", 10, 20);
if (testresult != 30) {
printf("got wrong result: %ld\n", testresult);
return 1;
}
testresult = addthem("idc", 30, 40.0, 'a');
if (testresult != (70+'a')) {
printf("got different wrong result: %ld\n", testresult);
return 1;
}
printf("%s: Success\n", argv[0]);
return 0;
}

View File

@ -0,0 +1,27 @@
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
/*
* voidarg.c
* testObjects
*
* Created by Blaine Garst on 2/17/09.
*
*/
// PURPOSE should complain about missing 'void' but both GCC and clang are supporting K&R instead
// CONFIG open error:
#include <stdio.h>
int Global;
void (^globalBlock)() = ^{ ++Global; }; // should be void (^gb)(void) = ...
int main(int argc, char *argv[]) {
printf("%s: success", argv[0]);
return 0;
}

55
CMakeLists.txt Normal file
View File

@ -0,0 +1,55 @@
# See docs/CMake.html for instructions about how to build Compiler-RT with CMake.
PROJECT( CompilerRT C )
CMAKE_MINIMUM_REQUIRED( VERSION 2.6 )
set(PACKAGE_NAME compiler-rt)
set(PACKAGE_VERSION 1.0svn)
set(PACKAGE_STRING "${PACKAGE_NAME} ${PACKAGE_VERSION}")
set(PACKAGE_BUGREPORT "llvmbugs@cs.uiuc.edu")
SET( CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/Modules )
# add definitions
include(DefineCompilerFlags)
# Disallow in-source build
INCLUDE( MacroEnsureOutOfSourceBuild )
MACRO_ENSURE_OUT_OF_SOURCE_BUILD(
"${PROJECT_NAME} requires an out of source build. Please create a separate build directory and run 'cmake /path/to/${PROJECT_NAME} [options]' there."
)
INCLUDE( ${CMAKE_SOURCE_DIR}/cmake/ConfigureChecks.cmake )
CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/cmake/config.h.cmake
${CMAKE_CURRENT_BINARY_DIR}/config.h )
INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_BINARY_DIR}
)
SET( Achitectures
i386 x86_64 ppc arm
)
SET( Configurations
Debug Release Profile
)
# Only build Blocks Runtime if the compiler has enough support
IF( WIN32 OR MSVC OR HAVE_OSATOMIC_COMPARE_AND_SWAP_INT OR HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT )
SET(BUILD_BLOCKS_RUNTIME TRUE)
ELSE( WIN32 OR MSVC OR HAVE_OSATOMIC_COMPARE_AND_SWAP_INT OR HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT )
SET(BUILD_BLOCKS_RUNTIME FALSE)
ENDIF( WIN32 OR MSVC OR HAVE_OSATOMIC_COMPARE_AND_SWAP_INT OR HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT )
IF( BUILD_BLOCKS_RUNTIME )
ADD_SUBDIRECTORY( BlocksRuntime )
ELSE( BUILD_BLOCKS_RUNTIME )
MESSAGE(STATUS "No suitable atomic operation routines detected, skipping Blocks Runtime")
ENDIF( BUILD_BLOCKS_RUNTIME )
ADD_SUBDIRECTORY( lib )
# Enable Test Suit:
INCLUDE( MacroAddCheckTest )
ADD_SUBDIRECTORY( test )

21
CREDITS.TXT Normal file
View File

@ -0,0 +1,21 @@
This file is a partial list of people who have contributed to the LLVM/CompilerRT
project. If you have contributed a patch or made some other contribution to
LLVM/CompilerRT, please submit a patch to this file to add yourself, and it will be
done!
The list is sorted by surname and formatted to allow easy grepping and
beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
(S).
N: Craig van Vliet
E: cvanvliet@auroraux.org
W: http://www.auroraux.org
D: Code style and Readability fixes.
N: Edward O'Callaghan
E: eocallaghan@auroraux.org
W: http://www.auroraux.org
D: CMake'ify Compiler-RT build system
D: Maintain Solaris & AuroraUX ports of Compiler-RT

63
LICENSE.TXT Normal file
View File

@ -0,0 +1,63 @@
==============================================================================
LLVM Release License
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2003-2009 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
LLVM Team
University of Illinois at Urbana-Champaign
http://llvm.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of the LLVM Team, University of Illinois at
Urbana-Champaign, nor the names of its contributors may be used to
endorse or promote products derived from this Software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
==============================================================================
Copyrights and Licenses for Third Party Software Distributed with LLVM:
==============================================================================
The LLVM software contains code written by third parties. Such software will
have its own individual LICENSE.TXT file in the directory in which it appears.
This file will describe the copyrights, license, and restrictions which apply
to that code.
The disclaimer of warranty in the University of Illinois Open Source License
applies to all code in the LLVM Distribution, and nothing in any of the
other licenses gives permission to use the names of the LLVM Team or the
University of Illinois to endorse or promote products derived from this
Software.
The following pieces of software have additional or alternate copyrights,
licenses, and/or restrictions:
Program Directory
------- ---------

243
Makefile Normal file
View File

@ -0,0 +1,243 @@
SubDirs := lib
# Set default rule before anything else.
all: help
include make/config.mk
include make/util.mk
# If SRCROOT is defined, assume we are doing an Apple style build. We should be
# able to use RC_XBS for this but that is unused during "make installsrc".
ifdef SRCROOT
include make/AppleBI.mk
endif
# Make sure we don't build with a missing ProjObjRoot.
ifeq ($(ProjObjRoot),)
$(error Refusing to build with empty ProjObjRoot variable)
endif
##############
###
# Rules
###
# Top level targets
# FIXME: Document the available subtargets.
help:
@echo "usage: make [{VARIABLE=VALUE}*] target"
@echo
@echo "User variables:"
@echo " VERBOSE=1: Use to show all commands [default=0]"
@echo
@echo "Available targets:"
@echo " <platform name>: build the libraries for 'platform'"
@echo " clean: clean all configurations"
@echo " test: run unit tests"
@echo
@echo " info-platforms: list available platforms"
@echo " help-devel: print additional help for developers"
@echo
help-devel: help
@echo "Development targets:"
@echo " <platform name>-<config name>:"
@echo " build the libraries for a single platform config"
@echo " <platform name>-<config name>-<arch name>:"
@echo " build the libraries for a single config and arch"
@echo " info-functions: list available compiler-rt functions"
@echo " help-hidden: print help for Makefile debugging"
@echo
help-hidden: help-devel
@echo "Debugging variables:"
@echo " DEBUGMAKE=1: enable some Makefile logging [default=]"
@echo " =2: enable more Makefile logging"
@echo
@echo "Debugging targets:"
@echo " make-print-FOO: print information on the variable 'FOO'"
@echo
info-functions:
@echo "compiler-rt Available Functions"
@echo
@echo "All Functions: $(AvailableFunctions)"
@$(foreach fn,$(AvailableFunctions),\
printf " %-20s - available in (%s)\n" $(fn)\
"$(foreach key,$(AvailableIn.$(fn)),$($(key).Dir))";)
info-platforms:
@echo "compiler-rt Available Platforms"
@echo
@echo "Platforms:"
@$(foreach key,$(PlatformKeys),\
printf " %s - from '%s'\n" $($(key).Name) $($(key).Path);\
printf " %s\n" "$($(key).Description)";\
printf " Configurations: %s\n\n" "$($(key).Configs)";)
# Provide default clean target which is extended by other templates.
.PHONY: clean
clean::
# Test
.PHONY: test
test:
cd test/Unit && ./test
###
# Directory handling magic.
# Create directories as needed, and timestamp their creation.
%/.dir:
$(Summary) " MKDIR: $*"
$(Verb) $(MKDIR) $* > /dev/null
$(Verb) $(DATE) > $@
# Remove directories
%/.remove:
$(Verb) $(RM) -r $*
###
# Include child makefile fragments
Dir := .
include make/subdir.mk
include make/lib_info.mk
include make/lib_util.mk
include make/lib_platforms.mk
###
# Define Platform Rules
define PerPlatform_template
$(call Set,Tmp.Key,$(1))
$(call Set,Tmp.Name,$($(Tmp.Key).Name))
$(call Set,Tmp.Configs,$($(Tmp.Key).Configs))
$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name))
# Top-Level Platform Target
$(Tmp.Name):: $(Tmp.Configs:%=$(Tmp.ObjPath)/%/libcompiler_rt.a)
.PHONY: $(Tmp.Name)
clean::
$(Verb) rm -rf $(Tmp.ObjPath)
# Per-Config Libraries
$(foreach config,$(Tmp.Configs),\
$(call PerPlatformConfig_template,$(config)))
endef
define PerPlatformConfig_template
$(call Set,Tmp.Config,$(1))
$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)/$(Tmp.Config))
# Compute the archs to build, depending on whether this is a universal build or
# not.
$(call Set,Tmp.ArchsToBuild,\
$(if $(call IsDefined,$(Tmp.Key).UniversalArchs),\
$(strip \
$(or $($(Tmp.Key).UniversalArchs.$(Tmp.Config)),\
$($(Tmp.Key).UniversalArchs))),\
$(call VarOrDefault,$(Tmp.Key).Arch.$(Tmp.Config),$($(Tmp.Key).Arch))))
# Copy or lipo to create the per-config library.
$(call Set,Tmp.Inputs,$(Tmp.ArchsToBuild:%=$(Tmp.ObjPath)/%/libcompiler_rt.a))
$(Tmp.ObjPath)/libcompiler_rt.a: $(Tmp.Inputs) $(Tmp.ObjPath)/.dir
$(Summary) " FINAL-ARCHIVE: $(Tmp.Name)/$(Tmp.Config): $$@"
-$(Verb) $(RM) $$@
$(if $(call streq,1,$(words $(Tmp.ArchsToBuild))), \
$(Verb) $(CP) $(Tmp.Inputs) $$@, \
$(Verb) $(LIPO) -create -output $$@ $(Tmp.Inputs))
.PRECIOUS: $(Tmp.ObjPath)/.dir
# Per-Config Targets
$(Tmp.Name)-$(Tmp.Config):: $(Tmp.ObjPath)/libcompiler_rt.a
.PHONY: $(Tmp.Name)-$(Tmp.Config)
# Per-Config-Arch Libraries
$(foreach arch,$(Tmp.ArchsToBuild),\
$(call PerPlatformConfigArch_template,$(arch)))
endef
define PerPlatformConfigArch_template
$(call Set,Tmp.Arch,$(1))
$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch))
$(call Set,Tmp.Functions,$(strip \
$(call GetCNAVar,FUNCTIONS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
$(call Set,Tmp.Optimized,$(strip \
$(call GetCNAVar,OPTIMIZED,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
$(call Set,Tmp.AR,$(strip \
$(call GetCNAVar,AR,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
$(call Set,Tmp.ARFLAGS,$(strip \
$(call GetCNAVar,ARFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
$(call Set,Tmp.RANLIB,$(strip \
$(call GetCNAVar,RANLIB,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
$(call Set,Tmp.RANLIBFLAGS,$(strip \
$(call GetCNAVar,RANLIBFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
# Compute the object inputs for this library.
$(call Set,Tmp.Inputs,\
$(foreach fn,$(sort $(Tmp.Functions)),\
$(call Set,Tmp.FnDir,\
$(call SelectFunctionDir,$(Tmp.Config),$(Tmp.Arch),$(fn),$(Tmp.Optimized)))\
$(Tmp.ObjPath)/$(Tmp.FnDir)/$(fn).o))
$(Tmp.ObjPath)/libcompiler_rt.a: $(Tmp.Inputs) $(Tmp.ObjPath)/.dir
$(Summary) " ARCHIVE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$@"
-$(Verb) $(RM) $$@
$(Verb) $(Tmp.AR) $(Tmp.ARFLAGS) $$@ $(Tmp.Inputs)
$(Verb) $(Tmp.RANLIB) $(Tmp.RANLIBFLAGS) $$@
.PRECIOUS: $(Tmp.ObjPath)/.dir
# Per-Config-Arch Targets
$(Tmp.Name)-$(Tmp.Config)-$(Tmp.Arch):: $(Tmp.ObjPath)/libcompiler_rt.a
.PHONY: $(Tmp.Name)-$(Tmp.Config)-$(Tmp.Arch)
# Per-Config-Arch-SubDir Objects
$(foreach key,$(SubDirKeys),\
$(call PerPlatformConfigArchSubDir_template,$(key)))
endef
define PerPlatformConfigArchSubDir_template
$(call Set,Tmp.SubDirKey,$(1))
$(call Set,Tmp.SubDir,$($(Tmp.SubDirKey).Dir))
$(call Set,Tmp.SrcPath,$(ProjSrcRoot)/$(Tmp.SubDir))
$(call Set,Tmp.ObjPath,$(ProjObjRoot)/$(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch)/$(Tmp.SubDirKey))
$(call Set,Tmp.Dependencies,$($(Tmp.SubDirKey).Dependencies))
$(call Set,Tmp.CC,$(strip \
$(call GetCNAVar,CC,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
$(call Set,Tmp.KERNEL_USE,$(strip \
$(call GetCNAVar,KERNEL_USE,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
$(call Set,Tmp.VISIBILITY_HIDDEN,$(strip \
$(call GetCNAVar,VISIBILITY_HIDDEN,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
$(call Set,Tmp.CFLAGS,$(strip \
$(if $(call IsDefined,$(Tmp.Key).UniversalArchs),-arch $(Tmp.Arch),)\
$(if $(call streq,$(Tmp.VISIBILITY_HIDDEN),1),\
-fvisibility=hidden -DVISIBILITY_HIDDEN,)\
$(if $(call streq,$(Tmp.KERNEL_USE),1),\
-mkernel -DKERNEL_USE,)\
$(call GetCNAVar,CFLAGS,$(Tmp.Key),$(Tmp.Config),$(Tmp.Arch))))
$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.s $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
$(Summary) " ASSEMBLE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$<
$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.S $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
$(Summary) " ASSEMBLE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$<
$(Tmp.ObjPath)/%.o: $(Tmp.SrcPath)/%.c $(Tmp.Dependencies) $(Tmp.ObjPath)/.dir
$(Summary) " COMPILE: $(Tmp.Name)/$(Tmp.Config)/$(Tmp.Arch): $$<"
$(Verb) $(Tmp.CC) $(Tmp.CFLAGS) -c -o $$@ $$<
.PRECIOUS: $(Tmp.ObjPath)/.dir
endef
# Run templates.
$(foreach key,$(PlatformKeys),\
$(eval $(call PerPlatform_template,$(key))))
###
ifneq ($(DEBUGMAKE),)
$(info MAKE: Done processing Makefile)
$(info )
endif

330
README.txt Normal file
View File

@ -0,0 +1,330 @@
Compiler-RT
================================
This directory and its subdirectories contain source code for the compiler
support routines.
Compiler-RT is open source software. You may freely distribute it under the
terms of the license agreement found in LICENSE.txt.
================================
This is a replacement library for libgcc. Each function is contained
in its own file. Each function has a corresponding unit test under
test/Unit.
A rudimentary script to test each file is in the file called
test/Unit/test.
Here is the specification for this library:
http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc
Here is a synopsis of the contents of this library:
typedef int si_int;
typedef unsigned su_int;
typedef long long di_int;
typedef unsigned long long du_int;
// Integral bit manipulation
di_int __ashldi3(di_int a, si_int b); // a << b
ti_int __ashlti3(ti_int a, si_int b); // a << b
di_int __ashrdi3(di_int a, si_int b); // a >> b arithmetic (sign fill)
ti_int __ashrti3(ti_int a, si_int b); // a >> b arithmetic (sign fill)
di_int __lshrdi3(di_int a, si_int b); // a >> b logical (zero fill)
ti_int __lshrti3(ti_int a, si_int b); // a >> b logical (zero fill)
si_int __clzsi2(si_int a); // count leading zeros
si_int __clzdi2(di_int a); // count leading zeros
si_int __clzti2(ti_int a); // count leading zeros
si_int __ctzsi2(si_int a); // count trailing zeros
si_int __ctzdi2(di_int a); // count trailing zeros
si_int __ctzti2(ti_int a); // count trailing zeros
si_int __ffsdi2(di_int a); // find least significant 1 bit
si_int __ffsti2(ti_int a); // find least significant 1 bit
si_int __paritysi2(si_int a); // bit parity
si_int __paritydi2(di_int a); // bit parity
si_int __parityti2(ti_int a); // bit parity
si_int __popcountsi2(si_int a); // bit population
si_int __popcountdi2(di_int a); // bit population
si_int __popcountti2(ti_int a); // bit population
uint32_t __bswapsi2(uint32_t a); // a byteswapped, arm only
uint64_t __bswapdi2(uint64_t a); // a byteswapped, arm only
// Integral arithmetic
di_int __negdi2 (di_int a); // -a
ti_int __negti2 (ti_int a); // -a
di_int __muldi3 (di_int a, di_int b); // a * b
ti_int __multi3 (ti_int a, ti_int b); // a * b
si_int __divsi3 (si_int a, si_int b); // a / b signed
di_int __divdi3 (di_int a, di_int b); // a / b signed
ti_int __divti3 (ti_int a, ti_int b); // a / b signed
su_int __udivsi3 (su_int n, su_int d); // a / b unsigned
du_int __udivdi3 (du_int a, du_int b); // a / b unsigned
tu_int __udivti3 (tu_int a, tu_int b); // a / b unsigned
si_int __modsi3 (si_int a, si_int b); // a % b signed
di_int __moddi3 (di_int a, di_int b); // a % b signed
ti_int __modti3 (ti_int a, ti_int b); // a % b signed
su_int __umodsi3 (su_int a, su_int b); // a % b unsigned
du_int __umoddi3 (du_int a, du_int b); // a % b unsigned
tu_int __umodti3 (tu_int a, tu_int b); // a % b unsigned
du_int __udivmoddi4(du_int a, du_int b, du_int* rem); // a / b, *rem = a % b
tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); // a / b, *rem = a % b
// Integral arithmetic with trapping overflow
si_int __absvsi2(si_int a); // abs(a)
di_int __absvdi2(di_int a); // abs(a)
ti_int __absvti2(ti_int a); // abs(a)
si_int __negvsi2(si_int a); // -a
di_int __negvdi2(di_int a); // -a
ti_int __negvti2(ti_int a); // -a
si_int __addvsi3(si_int a, si_int b); // a + b
di_int __addvdi3(di_int a, di_int b); // a + b
ti_int __addvti3(ti_int a, ti_int b); // a + b
si_int __subvsi3(si_int a, si_int b); // a - b
di_int __subvdi3(di_int a, di_int b); // a - b
ti_int __subvti3(ti_int a, ti_int b); // a - b
si_int __mulvsi3(si_int a, si_int b); // a * b
di_int __mulvdi3(di_int a, di_int b); // a * b
ti_int __mulvti3(ti_int a, ti_int b); // a * b
// Integral comparison: a < b -> 0
// a == b -> 1
// a > b -> 2
si_int __cmpdi2 (di_int a, di_int b);
si_int __cmpti2 (ti_int a, ti_int b);
si_int __ucmpdi2(du_int a, du_int b);
si_int __ucmpti2(tu_int a, tu_int b);
// Integral / floating point conversion
di_int __fixsfdi( float a);
di_int __fixdfdi( double a);
di_int __fixxfdi(long double a);
ti_int __fixsfti( float a);
ti_int __fixdfti( double a);
ti_int __fixxfti(long double a);
uint64_t __fixtfdi(long double input); // ppc only, doesn't match documentation
su_int __fixunssfsi( float a);
su_int __fixunsdfsi( double a);
su_int __fixunsxfsi(long double a);
du_int __fixunssfdi( float a);
du_int __fixunsdfdi( double a);
du_int __fixunsxfdi(long double a);
tu_int __fixunssfti( float a);
tu_int __fixunsdfti( double a);
tu_int __fixunsxfti(long double a);
uint64_t __fixunstfdi(long double input); // ppc only
float __floatdisf(di_int a);
double __floatdidf(di_int a);
long double __floatdixf(di_int a);
long double __floatditf(int64_t a); // ppc only
float __floattisf(ti_int a);
double __floattidf(ti_int a);
long double __floattixf(ti_int a);
float __floatundisf(du_int a);
double __floatundidf(du_int a);
long double __floatundixf(du_int a);
long double __floatunditf(uint64_t a); // ppc only
float __floatuntisf(tu_int a);
double __floatuntidf(tu_int a);
long double __floatuntixf(tu_int a);
// Floating point raised to integer power
float __powisf2( float a, si_int b); // a ^ b
double __powidf2( double a, si_int b); // a ^ b
long double __powixf2(long double a, si_int b); // a ^ b
long double __powitf2(long double a, si_int b); // ppc only, a ^ b
// Complex arithmetic
// (a + ib) * (c + id)
float _Complex __mulsc3( float a, float b, float c, float d);
double _Complex __muldc3(double a, double b, double c, double d);
long double _Complex __mulxc3(long double a, long double b,
long double c, long double d);
long double _Complex __multc3(long double a, long double b,
long double c, long double d); // ppc only
// (a + ib) / (c + id)
float _Complex __divsc3( float a, float b, float c, float d);
double _Complex __divdc3(double a, double b, double c, double d);
long double _Complex __divxc3(long double a, long double b,
long double c, long double d);
long double _Complex __divtc3(long double a, long double b,
long double c, long double d); // ppc only
// Runtime support
// __clear_cache() is used to tell process that new instructions have been
// written to an address range. Necessary on processors that do not have
// a unified instuction and data cache.
void __clear_cache(void* start, void* end);
// __enable_execute_stack() is used with nested functions when a trampoline
// function is written onto the stack and that page range needs to be made
// executable.
void __enable_execute_stack(void* addr);
// __gcc_personality_v0() is normally only called by the system unwinder.
// C code (as opposed to C++) normally does not need a personality function
// because there are no catch clauses or destructors to be run. But there
// is a C language extension __attribute__((cleanup(func))) which marks local
// variables as needing the cleanup function "func" to be run when the
// variable goes out of scope. That includes when an exception is thrown,
// so a personality handler is needed.
_Unwind_Reason_Code __gcc_personality_v0(int version, _Unwind_Action actions,
uint64_t exceptionClass, struct _Unwind_Exception* exceptionObject,
_Unwind_Context_t context);
// for use with some implementations of assert() in <assert.h>
void __eprintf(const char* format, const char* assertion_expression,
const char* line, const char* file);
// Power PC specific functions
// There is no C interface to the saveFP/restFP functions. They are helper
// functions called by the prolog and epilog of functions that need to save
// a number of non-volatile float point registers.
saveFP
restFP
// PowerPC has a standard template for trampoline functions. This function
// generates a custom trampoline function with the specific realFunc
// and localsPtr values.
void __trampoline_setup(uint32_t* trampOnStack, int trampSizeAllocated,
const void* realFunc, void* localsPtr);
// adds two 128-bit double-double precision values ( x + y )
long double __gcc_qadd(long double x, long double y);
// subtracts two 128-bit double-double precision values ( x - y )
long double __gcc_qsub(long double x, long double y);
// multiples two 128-bit double-double precision values ( x * y )
long double __gcc_qmul(long double x, long double y);
// divides two 128-bit double-double precision values ( x / y )
long double __gcc_qdiv(long double a, long double b);
// ARM specific functions
// There is no C interface to the switch* functions. These helper functions
// are only needed by Thumb1 code for efficient switch table generation.
switch16
switch32
switch8
switchu8
// There is no C interface to the *_vfp_d8_d15_regs functions. There are
// called in the prolog and epilog of Thumb1 functions. When the C++ ABI use
// SJLJ for exceptions, each function with a catch clause or destuctors needs
// to save and restore all registers in it prolog and epliog. But there is
// no way to access vector and high float registers from thumb1 code, so the
// compiler must add call outs to these helper functions in the prolog and
// epilog.
restore_vfp_d8_d15_regs
save_vfp_d8_d15_regs
// Note: long ago ARM processors did not have floating point hardware support.
// Floating point was done in software and floating point parameters were
// passed in integer registers. When hardware support was added for floating
// point, new *vfp functions were added to do the same operations but with
// floating point parameters in floating point registers.
// Undocumented functions
float __addsf3vfp(float a, float b); // Appears to return a + b
double __adddf3vfp(double a, double b); // Appears to return a + b
float __divsf3vfp(float a, float b); // Appears to return a / b
double __divdf3vfp(double a, double b); // Appears to return a / b
int __eqsf2vfp(float a, float b); // Appears to return one
// iff a == b and neither is NaN.
int __eqdf2vfp(double a, double b); // Appears to return one
// iff a == b and neither is NaN.
double __extendsfdf2vfp(float a); // Appears to convert from
// float to double.
int __fixdfsivfp(double a); // Appears to convert from
// double to int.
int __fixsfsivfp(float a); // Appears to convert from
// float to int.
unsigned int __fixunssfsivfp(float a); // Appears to convert from
// float to unsigned int.
unsigned int __fixunsdfsivfp(double a); // Appears to convert from
// double to unsigned int.
double __floatsidfvfp(int a); // Appears to convert from
// int to double.
float __floatsisfvfp(int a); // Appears to convert from
// int to float.
double __floatunssidfvfp(unsigned int a); // Appears to convert from
// unisgned int to double.
float __floatunssisfvfp(unsigned int a); // Appears to convert from
// unisgned int to float.
int __gedf2vfp(double a, double b); // Appears to return __gedf2
// (a >= b)
int __gesf2vfp(float a, float b); // Appears to return __gesf2
// (a >= b)
int __gtdf2vfp(double a, double b); // Appears to return __gtdf2
// (a > b)
int __gtsf2vfp(float a, float b); // Appears to return __gtsf2
// (a > b)
int __ledf2vfp(double a, double b); // Appears to return __ledf2
// (a <= b)
int __lesf2vfp(float a, float b); // Appears to return __lesf2
// (a <= b)
int __ltdf2vfp(double a, double b); // Appears to return __ltdf2
// (a < b)
int __ltsf2vfp(float a, float b); // Appears to return __ltsf2
// (a < b)
double __muldf3vfp(double a, double b); // Appears to return a * b
float __mulsf3vfp(float a, float b); // Appears to return a * b
int __nedf2vfp(double a, double b); // Appears to return __nedf2
// (a != b)
double __negdf2vfp(double a); // Appears to return -a
float __negsf2vfp(float a); // Appears to return -a
float __negsf2vfp(float a); // Appears to return -a
double __subdf3vfp(double a, double b); // Appears to return a - b
float __subsf3vfp(float a, float b); // Appears to return a - b
float __truncdfsf2vfp(double a); // Appears to convert from
// double to float.
int __unorddf2vfp(double a, double b); // Appears to return __unorddf2
int __unordsf2vfp(float a, float b); // Appears to return __unordsf2
Preconditions are listed for each function at the definition when there are any.
Any preconditions reflect the specification at
http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html#Libgcc.
Assumptions are listed in "int_lib.h", and in individual files. Where possible
assumptions are checked at compile time.

View File

@ -0,0 +1,38 @@
INCLUDE( CheckIncludeFile )
INCLUDE( CheckFunctionExists )
INCLUDE( CheckSymbolExists )
INCLUDE( CheckCSourceCompiles )
SET( PACKAGE ${PACKAGE_NAME} )
SET( VERSION ${PACKAGE_VERSION} )
SET( BINARYDIR ${CMAKE_BINARY_DIR} )
SET( SOURCEDIR ${CMAKE_SOURCE_DIR} )
# HEADER FILES
CHECK_INCLUDE_FILE( sys/byteorder.h HAVE_SYS_BYTEORDER_H )
CHECK_INCLUDE_FILE( AvailabilityMacros.h HAVE_AVAILABILITY_MACROS_H )
CHECK_INCLUDE_FILE( TargetConditionals.h HAVE_TARGET_CONDITIONALS_H )
CHECK_INCLUDE_FILE( libkern/OSAtomic.h HAVE_LIBKERN_OSATOMIC_H )
# FUNCTIONS
CHECK_FUNCTION_EXISTS( sysconf HAVE_SYSCONF )
CHECK_SYMBOL_EXISTS( OSAtomicCompareAndSwapInt libkern/OSAtomic.h HAVE_OSATOMIC_COMPARE_AND_SWAP_INT )
CHECK_SYMBOL_EXISTS( OSAtomicCompareAndSwapLong libkern/OSAtomic.h HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG )
# BUILTIN
CHECK_C_SOURCE_COMPILES( "
volatile int a;
int main(int argc, char *argv[]) {
(void)__sync_bool_compare_and_swap(&a, 1, 2);
return 0;
}
" HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT )
CHECK_C_SOURCE_COMPILES( "
volatile long a;
int main(int argc, char *argv[]) {
(void)__sync_bool_compare_and_swap(&a, 1, 2);
return 0;
}
" HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG )

View File

@ -0,0 +1,6 @@
# Define compiler flags
if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX )
#ADD_DEFINITIONS( -Wall -W -Werror -pedantic )
ADD_DEFINITIONS( -std=c99 -Wall -Wextra -W -pedantic -Wno-unused-parameter )
endif( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX )

View File

@ -0,0 +1,12 @@
# - macro_add_check_test(test_name test_source linklib1 ... linklibN)
ENABLE_TESTING()
include(CTest)
set(CMAKE_C_FLAGS_PROFILING "-g -pg")
macro (MACRO_ADD_CHECK_TEST _testName _testSource)
add_executable(${_testName} ${_testSource})
target_link_libraries(${_testName} ${ARGN})
get_target_property(_targetLocation ${_testName} LOCATION)
add_test(${_testName} ${_targetLocation})
endmacro (MACRO_ADD_CHECK_TEST)

View File

@ -0,0 +1,18 @@
# MACRO_ENSURE_OUT_OF_SOURCE_BUILD(<errorMessage>)
macro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD _errorMessage )
string( COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${CMAKE_BINARY_DIR}" _insource )
if( _insource )
message( SEND_ERROR "${_errorMessage}" )
message( FATAL_ERROR
"In-source builds are not allowed.
CMake would overwrite the makefiles distributed with Compiler-RT.
Please create a directory and run cmake from there, passing the path
to this source directory as the last argument.
This process created the file `CMakeCache.txt' and the directory `CMakeFiles'.
Please delete them."
)
endif( _insource )
endmacro( MACRO_ENSURE_OUT_OF_SOURCE_BUILD )

12
cmake/config.h.cmake Normal file
View File

@ -0,0 +1,12 @@
#cmakedefine HAVE_SYS_BYTEORDER_H ${HAVE_SYS_BYTEORDER}
#cmakedefine HAVE_AVAILABILITY_MACROS_H ${HAVE_AVAILABILITY_MACROS_H}
#cmakedefine HAVE_TARGET_CONDITIONALS_H ${HAVE_TARGET_CONDITIONALS_H}
#cmakedefine HAVE_LIBKERN_OSATOMIC_H ${HAVE_LIBKERN_OSATOMIC_H}
#cmakedefine HAVE_SYSCONF ${HAVE_SYSCONF}
#cmakedefine HAVE_OSATOMIC_COMPARE_AND_SWAP_INT ${HAVE_OSATOMIC_COMPARE_AND_SWAP_INT}
#cmakedefine HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG ${HAVE_OSATOMIC_COMPARE_AND_SWAP_LONG}
#cmakedefine HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT ${HAVE_SYNC_BOOL_COMPARE_AND_SWAP_INT}
#cmakedefine HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG ${HAVE_SYNC_BOOL_COMPARE_AND_SWAP_LONG}

81
lib/CMakeLists.txt Normal file
View File

@ -0,0 +1,81 @@
#
# Create a library called "CompilerRT" which includes the source files.
#INCLUDE_DIRECTORIES(
# ${CMAKE_CURRENT_BINARY_DIR}
#)
# Generic functions needed for each architecture
# libcompiler_rt.Generic.a libcompiler_rt.Optimized.a
# Generic
SET( Generic_SRCS
absvdi2.c absvsi2.c addvdi3.c addvsi3.c ashldi3.c ashrdi3.c
clzdi2.c clzsi2.c cmpdi2.c ctzdi2.c ctzsi2.c
divdc3.c divdi3.c divsc3.c ffsdi2.c
fixdfdi.c fixsfdi.c fixunsdfdi.c fixunsdfsi.c fixunssfdi.c
fixunssfsi.c floatdidf.c floatdisf.c floatundidf.c floatundisf.c
gcc_personality_v0.c lshrdi3.c moddi3.c muldc3.c muldi3.c
mulsc3.c mulvdi3.c mulvsi3.c negdi2.c negvdi2.c negvsi2.c
paritydi2.c paritysi2.c popcountdi2.c popcountsi2.c powidf2.c
powisf2.c subvdi3.c subvsi3.c ucmpdi2.c udivdi3.c
udivmoddi4.c umoddi3.c apple_versioning.c eprintf.c
)
# Optimized functions for each architecture
# Commenting out for the min until the basics are working first.
# ADD_SUBDIRECTORY( ppc )
# ADD_SUBDIRECTORY( x86_64 )
# ADD_SUBDIRECTORY( i386 )
# ADD_SUBDIRECTORY( arm )
# List of functions needed for each architecture.
SET( i386_Functions
divxc3.c fixunsxfdi.c fixunsxfsi.c fixxfdi.c floatdixf.c
floatundixf.c mulxc3.c powixf2.c clear_cache.c enable_execute_stack.c
)
SET( x86_64_Functions
absvti2.c addvti3.c ashlti3.c ashrti3.c clzti2.c cmpti2.c
ctzti2.c divti3.c divxc3.c ffsti2.c fixdfti.c fixsfti.c
fixunsdfti.c fixunssfti.c fixunsxfdi.c fixunsxfsi.c
fixunsxfti.c fixxfdi.c fixxfti.c floatdixf.c floattidf.c
floattisf.c floattixf.c floatundixf.c floatuntidf.c
floatuntisf.c floatuntixf.c lshrti3.c modti3.c multi3.c
mulvti3.c mulxc3.c negti2.c negvti2.c parityti2.c
popcountti2.c powixf2.c subvti3.c ucmpti2.c udivmodti4.c
udivti3.c umodti3.c clear_cache.c enable_execute_stack.c
)
SET( PPC_Functions
divtc3.c fixtfdi.c fixunstfdi.c floatditf.c floatunditf.c
gcc_qadd.c gcc_qdiv.c gcc_qmul.c gcc_qsub.c multc3.c
powitf2.c restFP.c saveFP.c trampoline_setup.c
clear_cache.c enable_execute_stack.c
)
SET( ARM_Functions
adddf3vfp.c addsf3vfp.c bswapdi2.c bswapsi2.c divdf3vfp.c
divsf3vfp.c eqdf2vfp.c eqsf2vfp.c extendsfdf2vfp.c
fixdfsivfp.c fixsfsivfp.c fixunsdfsivfp.c fixunssfsivfp.c
floatsidfvfp.c floatsisfvfp.c floatunssidfvfp.c floatunssisfvfp.c
gedf2vfp.c gesf2vfp.c gtdf2vfp.c gtsf2vfp.c
ledf2vfp.c lesf2vfp.c ltdf2vfp.c ltsf2vfp.c
muldf3vfp.c mulsf3vfp.c
nedf2vfp.c negdf2vfp.c negsf2vfp.c nesf2vfp.c
subdf3vfp.c subsf3vfp.c truncdfsf2vfp.c unorddf2vfp.c unordsf2vfp.c
modsi3.c umodsi3.c udivsi3.c divsi3.c switch.c
)
#FOREACH( LOOP_VAR ${Achitectures} )
# See ARCHIVE_OUTPUT_DIRECTORY docs.
#${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/${LOOP_VAR}
#ENDFOREACH
ADD_LIBRARY( ${PROJECT_NAME}-Generic STATIC ${Generic_SRCS} )
#ADD_LIBRARY( ${PROJECT_NAME}-i386 STATIC ${i386_Functions} )
# [[debug|optimized|general]
#TARGET_LINK_LIBRARIES( ${PROJECT_NAME} ${PROJECT_NAME}-Common optimized ${PROJECT_NAME}-i386 )

17
lib/Makefile.mk Normal file
View File

@ -0,0 +1,17 @@
#===- lib/Makefile.mk --------------------------------------*- Makefile -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
SubDirs := i386 ppc x86_64 arm
Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
ObjNames := $(Sources:%.c=%.o)
Implementation := Generic
# FIXME: use automatic dependencies?
Dependencies := $(wildcard $(Dir)/*.h)

30
lib/absvdi2.c Normal file
View File

@ -0,0 +1,30 @@
/*===-- absvdi2.c - Implement __absvdi2 -----------------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
*
*===----------------------------------------------------------------------===
*
* This file implements __absvdi2 for the compiler_rt library.
*
*===----------------------------------------------------------------------===
*/
#include "int_lib.h"
#include <stdlib.h>
/* Returns: absolute value */
/* Effects: aborts if abs(x) < 0 */
di_int
__absvdi2(di_int a)
{
const int N = (int)(sizeof(di_int) * CHAR_BIT);
if (a == ((di_int)1 << (N-1)))
compilerrt_abort();
const di_int t = a >> (N - 1);
return (a ^ t) - t;
}

30
lib/absvsi2.c Normal file
View File

@ -0,0 +1,30 @@
/* ===-- absvsi2.c - Implement __absvsi2 -----------------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
*
* ===----------------------------------------------------------------------===
*
* This file implements __absvsi2 for the compiler_rt library.
*
* ===----------------------------------------------------------------------===
*/
#include "int_lib.h"
#include <stdlib.h>
/* Returns: absolute value */
/* Effects: aborts if abs(x) < 0 */
si_int
__absvsi2(si_int a)
{
const int N = (int)(sizeof(si_int) * CHAR_BIT);
if (a == (1 << (N-1)))
compilerrt_abort();
const si_int t = a >> (N - 1);
return (a ^ t) - t;
}

34
lib/absvti2.c Normal file
View File

@ -0,0 +1,34 @@
/* ===-- absvti2.c - Implement __absvdi2 -----------------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
*
* ===----------------------------------------------------------------------===
*
* This file implements __absvti2 for the compiler_rt library.
*
* ===----------------------------------------------------------------------===
*/
#if __x86_64
#include "int_lib.h"
#include <stdlib.h>
/* Returns: absolute value */
/* Effects: aborts if abs(x) < 0 */
ti_int
__absvti2(ti_int a)
{
const int N = (int)(sizeof(ti_int) * CHAR_BIT);
if (a == ((ti_int)1 << (N-1)))
compilerrt_abort();
const ti_int s = a >> (N - 1);
return (a ^ s) - s;
}
#endif

154
lib/adddf3.c Normal file
View File

@ -0,0 +1,154 @@
//===-- lib/adddf3.c - Double-precision addition and subtraction --*- C -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements double-precision soft-float addition and subtraction
// with the IEEE-754 default rounding (to nearest, ties to even).
//
//===----------------------------------------------------------------------===//
#define DOUBLE_PRECISION
#include "fp_lib.h"
fp_t __adddf3(fp_t a, fp_t b) {
rep_t aRep = toRep(a);
rep_t bRep = toRep(b);
const rep_t aAbs = aRep & absMask;
const rep_t bAbs = bRep & absMask;
// Detect if a or b is zero, infinity, or NaN.
if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) {
// NaN + anything = qNaN
if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
// anything + NaN = qNaN
if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
if (aAbs == infRep) {
// +/-infinity + -/+infinity = qNaN
if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
// +/-infinity + anything remaining = +/- infinity
else return a;
}
// anything remaining + +/-infinity = +/-infinity
if (bAbs == infRep) return b;
// zero + anything = anything
if (!aAbs) {
// but we need to get the sign right for zero + zero
if (!bAbs) return fromRep(toRep(a) & toRep(b));
else return b;
}
// anything + zero = anything
if (!bAbs) return a;
}
// Swap a and b if necessary so that a has the larger absolute value.
if (bAbs > aAbs) {
const rep_t temp = aRep;
aRep = bRep;
bRep = temp;
}
// Extract the exponent and significand from the (possibly swapped) a and b.
int aExponent = aRep >> significandBits & maxExponent;
int bExponent = bRep >> significandBits & maxExponent;
rep_t aSignificand = aRep & significandMask;
rep_t bSignificand = bRep & significandMask;
// Normalize any denormals, and adjust the exponent accordingly.
if (aExponent == 0) aExponent = normalize(&aSignificand);
if (bExponent == 0) bExponent = normalize(&bSignificand);
// The sign of the result is the sign of the larger operand, a. If they
// have opposite signs, we are performing a subtraction; otherwise addition.
const rep_t resultSign = aRep & signBit;
const bool subtraction = (aRep ^ bRep) & signBit;
// Shift the significands to give us round, guard and sticky, and or in the
// implicit significand bit. (If we fell through from the denormal path it
// was already set by normalize( ), but setting it twice won't hurt
// anything.)
aSignificand = (aSignificand | implicitBit) << 3;
bSignificand = (bSignificand | implicitBit) << 3;
// Shift the significand of b by the difference in exponents, with a sticky
// bottom bit to get rounding correct.
const int align = aExponent - bExponent;
if (align) {
if (align < typeWidth) {
const bool sticky = bSignificand << (typeWidth - align);
bSignificand = bSignificand >> align | sticky;
} else {
bSignificand = 1; // sticky; b is known to be non-zero.
}
}
if (subtraction) {
aSignificand -= bSignificand;
// If a == -b, return +zero.
if (aSignificand == 0) return fromRep(0);
// If partial cancellation occured, we need to left-shift the result
// and adjust the exponent:
if (aSignificand < implicitBit << 3) {
const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
aSignificand <<= shift;
aExponent -= shift;
}
}
else /* addition */ {
aSignificand += bSignificand;
// If the addition carried up, we need to right-shift the result and
// adjust the exponent:
if (aSignificand & implicitBit << 4) {
const bool sticky = aSignificand & 1;
aSignificand = aSignificand >> 1 | sticky;
aExponent += 1;
}
}
// If we have overflowed the type, return +/- infinity:
if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
if (aExponent <= 0) {
// Result is denormal before rounding; the exponent is zero and we
// need to shift the significand.
const int shift = 1 - aExponent;
const bool sticky = aSignificand << (typeWidth - shift);
aSignificand = aSignificand >> shift | sticky;
aExponent = 0;
}
// Low three bits are round, guard, and sticky.
const int roundGuardSticky = aSignificand & 0x7;
// Shift the significand into place, and mask off the implicit bit.
rep_t result = aSignificand >> 3 & significandMask;
// Insert the exponent and sign.
result |= (rep_t)aExponent << significandBits;
result |= resultSign;
// Final rounding. The result may overflow to infinity, but that is the
// correct result in that case.
if (roundGuardSticky > 0x4) result++;
if (roundGuardSticky == 0x4) result += result & 1;
return fromRep(result);
}
// Subtraction; flip the sign bit of b and add.
fp_t __subdf3(fp_t a, fp_t b) {
return __adddf3(a, fromRep(toRep(b) ^ signBit));
}

164
lib/addsf3.c Normal file
View File

@ -0,0 +1,164 @@
//===-- lib/addsf3.c - Single-precision addition and subtraction --*- C -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements single-precision soft-float addition and subtraction
// with the IEEE-754 default rounding (to nearest, ties to even).
//
//===----------------------------------------------------------------------===//
#define SINGLE_PRECISION
#include "fp_lib.h"
fp_t __addsf3(fp_t a, fp_t b) {
rep_t aRep = toRep(a);
rep_t bRep = toRep(b);
const rep_t aAbs = aRep & absMask;
const rep_t bAbs = bRep & absMask;
// Detect if a or b is zero, infinity, or NaN.
if (aAbs - 1U >= infRep - 1U || bAbs - 1U >= infRep - 1U) {
// NaN + anything = qNaN
if (aAbs > infRep) return fromRep(toRep(a) | quietBit);
// anything + NaN = qNaN
if (bAbs > infRep) return fromRep(toRep(b) | quietBit);
if (aAbs == infRep) {
// +/-infinity + -/+infinity = qNaN
if ((toRep(a) ^ toRep(b)) == signBit) return fromRep(qnanRep);
// +/-infinity + anything remaining = +/- infinity
else return a;
}
// anything remaining + +/-infinity = +/-infinity
if (bAbs == infRep) return b;
// zero + anything = anything
if (!aAbs) {
// but we need to get the sign right for zero + zero
if (!bAbs) return fromRep(toRep(a) & toRep(b));
else return b;
}
// anything + zero = anything
if (!bAbs) return a;
}
// Swap a and b if necessary so that a has the larger absolute value.
if (bAbs > aAbs) {
const rep_t temp = aRep;
aRep = bRep;
bRep = temp;
}
// Extract the exponent and significand from the (possibly swapped) a and b.
int aExponent = aRep >> significandBits & maxExponent;
int bExponent = bRep >> significandBits & maxExponent;
rep_t aSignificand = aRep & significandMask;
rep_t bSignificand = bRep & significandMask;
// Normalize any denormals, and adjust the exponent accordingly.
if (aExponent == 0) aExponent = normalize(&aSignificand);
if (bExponent == 0) bExponent = normalize(&bSignificand);
// The sign of the result is the sign of the larger operand, a. If they
// have opposite signs, we are performing a subtraction; otherwise addition.
const rep_t resultSign = aRep & signBit;
const bool subtraction = (aRep ^ bRep) & signBit;
// Shift the significands to give us round, guard and sticky, and or in the
// implicit significand bit. (If we fell through from the denormal path it
// was already set by normalize( ), but setting it twice won't hurt
// anything.)
aSignificand = (aSignificand | implicitBit) << 3;
bSignificand = (bSignificand | implicitBit) << 3;
// Shift the significand of b by the difference in exponents, with a sticky
// bottom bit to get rounding correct.
const int align = aExponent - bExponent;
if (align) {
if (align < typeWidth) {
const bool sticky = bSignificand << (typeWidth - align);
bSignificand = bSignificand >> align | sticky;
} else {
bSignificand = 1; // sticky; b is known to be non-zero.
}
}
if (subtraction) {
aSignificand -= bSignificand;
// If a == -b, return +zero.
if (aSignificand == 0) return fromRep(0);
// If partial cancellation occured, we need to left-shift the result
// and adjust the exponent:
if (aSignificand < implicitBit << 3) {
const int shift = rep_clz(aSignificand) - rep_clz(implicitBit << 3);
aSignificand <<= shift;
aExponent -= shift;
}
}
else /* addition */ {
aSignificand += bSignificand;
// If the addition carried up, we need to right-shift the result and
// adjust the exponent:
if (aSignificand & implicitBit << 4) {
const bool sticky = aSignificand & 1;
aSignificand = aSignificand >> 1 | sticky;
aExponent += 1;
}
}
// If we have overflowed the type, return +/- infinity:
if (aExponent >= maxExponent) return fromRep(infRep | resultSign);
if (aExponent <= 0) {
// Result is denormal before rounding; the exponent is zero and we
// need to shift the significand.
const int shift = 1 - aExponent;
const bool sticky = aSignificand << (typeWidth - shift);
aSignificand = aSignificand >> shift | sticky;
aExponent = 0;
}
// Low three bits are round, guard, and sticky.
const int roundGuardSticky = aSignificand & 0x7;
// Shift the significand into place, and mask off the implicit bit.
rep_t result = aSignificand >> 3 & significandMask;
// Insert the exponent and sign.
result |= (rep_t)aExponent << significandBits;
result |= resultSign;
// Final rounding. The result may overflow to infinity, but that is the
// correct result in that case.
if (roundGuardSticky > 0x4) result++;
if (roundGuardSticky == 0x4) result += result & 1;
return fromRep(result);
}
// Subtraction; flip the sign bit of b and add.
fp_t __subsf3(fp_t a, fp_t b) {
return __addsf3(a, fromRep(toRep(b) ^ signBit));
}

37
lib/addvdi3.c Normal file
View File

@ -0,0 +1,37 @@
/* ===-- addvdi3.c - Implement __addvdi3 -----------------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
*
* ===----------------------------------------------------------------------===
*
* This file implements __addvdi3 for the compiler_rt library.
*
* ===----------------------------------------------------------------------===
*/
#include "int_lib.h"
#include <stdlib.h>
/* Returns: a + b */
/* Effects: aborts if a + b overflows */
di_int
__addvdi3(di_int a, di_int b)
{
di_int s = a + b;
if (b >= 0)
{
if (s < a)
compilerrt_abort();
}
else
{
if (s >= a)
compilerrt_abort();
}
return s;
}

37
lib/addvsi3.c Normal file
View File

@ -0,0 +1,37 @@
/* ===-- addvsi3.c - Implement __addvsi3 -----------------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
*
* ===----------------------------------------------------------------------===
*
* This file implements __addvsi3 for the compiler_rt library.
*
* ===----------------------------------------------------------------------===
*/
#include "int_lib.h"
#include <stdlib.h>
/* Returns: a + b */
/* Effects: aborts if a + b overflows */
si_int
__addvsi3(si_int a, si_int b)
{
si_int s = a + b;
if (b >= 0)
{
if (s < a)
compilerrt_abort();
}
else
{
if (s >= a)
compilerrt_abort();
}
return s;
}

41
lib/addvti3.c Normal file
View File

@ -0,0 +1,41 @@
/* ===-- addvti3.c - Implement __addvti3 -----------------------------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
*
* ===----------------------------------------------------------------------===
*
* This file implements __addvti3 for the compiler_rt library.
*
* ===----------------------------------------------------------------------===
*/
#if __x86_64
#include "int_lib.h"
#include <stdlib.h>
/* Returns: a + b */
/* Effects: aborts if a + b overflows */
ti_int
__addvti3(ti_int a, ti_int b)
{
ti_int s = a + b;
if (b >= 0)
{
if (s < a)
compilerrt_abort();
}
else
{
if (s >= a)
compilerrt_abort();
}
return s;
}
#endif

150
lib/apple_versioning.c Normal file
View File

@ -0,0 +1,150 @@
/* ===-- apple_versioning.c - Adds versioning symbols for ld ---------------===
*
* The LLVM Compiler Infrastructure
*
* This file is distributed under the University of Illinois Open Source
* License. See LICENSE.TXT for details.
*
* ===----------------------------------------------------------------------===
*/
#if __APPLE__
#if __arm__
#define NOT_HERE_BEFORE_10_6(sym)
#elif __ppc__
#define NOT_HERE_BEFORE_10_6(sym) \
extern const char sym##_tmp3 __asm("$ld$hide$os10.3$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp3 = 0; \
extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp5 = 0;
#else
#define NOT_HERE_BEFORE_10_6(sym) \
extern const char sym##_tmp4 __asm("$ld$hide$os10.4$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp4 = 0; \
extern const char sym##_tmp5 __asm("$ld$hide$os10.5$_" #sym ); \
__attribute__((visibility("default"))) const char sym##_tmp5 = 0;
#endif /* __ppc__ */
/* Symbols in libSystem.dylib in 10.6 and later,
* but are in libgcc_s.dylib in earlier versions
*/
NOT_HERE_BEFORE_10_6(__absvdi2)
NOT_HERE_BEFORE_10_6(__absvsi2)
NOT_HERE_BEFORE_10_6(__absvti2)
NOT_HERE_BEFORE_10_6(__addvdi3)
NOT_HERE_BEFORE_10_6(__addvsi3)
NOT_HERE_BEFORE_10_6(__addvti3)
NOT_HERE_BEFORE_10_6(__ashldi3)
NOT_HERE_BEFORE_10_6(__ashlti3)
NOT_HERE_BEFORE_10_6(__ashrdi3)
NOT_HERE_BEFORE_10_6(__ashrti3)
NOT_HERE_BEFORE_10_6(__clear_cache)
NOT_HERE_BEFORE_10_6(__clzdi2)
NOT_HERE_BEFORE_10_6(__clzsi2)
NOT_HERE_BEFORE_10_6(__clzti2)
NOT_HERE_BEFORE_10_6(__cmpdi2)
NOT_HERE_BEFORE_10_6(__cmpti2)
NOT_HERE_BEFORE_10_6(__ctzdi2)
NOT_HERE_BEFORE_10_6(__ctzsi2)
NOT_HERE_BEFORE_10_6(__ctzti2)
NOT_HERE_BEFORE_10_6(__divdc3)
NOT_HERE_BEFORE_10_6(__divdi3)
NOT_HERE_BEFORE_10_6(__divsc3)
NOT_HERE_BEFORE_10_6(__divtc3)
NOT_HERE_BEFORE_10_6(__divti3)
NOT_HERE_BEFORE_10_6(__divxc3)
NOT_HERE_BEFORE_10_6(__enable_execute_stack)
NOT_HERE_BEFORE_10_6(__ffsdi2)
NOT_HERE_BEFORE_10_6(__ffsti2)
NOT_HERE_BEFORE_10_6(__fixdfdi)
NOT_HERE_BEFORE_10_6(__fixdfti)
NOT_HERE_BEFORE_10_6(__fixsfdi)
NOT_HERE_BEFORE_10_6(__fixsfti)
NOT_HERE_BEFORE_10_6(__fixtfdi)
NOT_HERE_BEFORE_10_6(__fixunsdfdi)
NOT_HERE_BEFORE_10_6(__fixunsdfsi)
NOT_HERE_BEFORE_10_6(__fixunsdfti)
NOT_HERE_BEFORE_10_6(__fixunssfdi)
NOT_HERE_BEFORE_10_6(__fixunssfsi)
NOT_HERE_BEFORE_10_6(__fixunssfti)
NOT_HERE_BEFORE_10_6(__fixunstfdi)
NOT_HERE_BEFORE_10_6(__fixunsxfdi)
NOT_HERE_BEFORE_10_6(__fixunsxfsi)
NOT_HERE_BEFORE_10_6(__fixunsxfti)
NOT_HERE_BEFORE_10_6(__fixxfdi)
NOT_HERE_BEFORE_10_6(__fixxfti)
NOT_HERE_BEFORE_10_6(__floatdidf)
NOT_HERE_BEFORE_10_6(__floatdisf)
NOT_HERE_BEFORE_10_6(__floatditf)
NOT_HERE_BEFORE_10_6(__floatdixf)
NOT_HERE_BEFORE_10_6(__floattidf)
NOT_HERE_BEFORE_10_6(__floattisf)
NOT_HERE_BEFORE_10_6(__floattixf)
NOT_HERE_BEFORE_10_6(__floatundidf)
NOT_HERE_BEFORE_10_6(__floatundisf)
NOT_HERE_BEFORE_10_6(__floatunditf)
NOT_HERE_BEFORE_10_6(__floatundixf)
NOT_HERE_BEFORE_10_6(__floatuntidf)
NOT_HERE_BEFORE_10_6(__floatuntisf)
NOT_HERE_BEFORE_10_6(__floatuntixf)
NOT_HERE_BEFORE_10_6(__gcc_personality_v0)
NOT_HERE_BEFORE_10_6(__lshrdi3)
NOT_HERE_BEFORE_10_6(__lshrti3)
NOT_HERE_BEFORE_10_6(__moddi3)
NOT_HERE_BEFORE_10_6(__modti3)
NOT_HERE_BEFORE_10_6(__muldc3)
NOT_HERE_BEFORE_10_6(__muldi3)
NOT_HERE_BEFORE_10_6(__mulsc3)
NOT_HERE_BEFORE_10_6(__multc3)
NOT_HERE_BEFORE_10_6(__multi3)
NOT_HERE_BEFORE_10_6(__mulvdi3)
NOT_HERE_BEFORE_10_6(__mulvsi3)
NOT_HERE_BEFORE_10_6(__mulvti3)
NOT_HERE_BEFORE_10_6(__mulxc3)
NOT_HERE_BEFORE_10_6(__negdi2)
NOT_HERE_BEFORE_10_6(__negti2)
NOT_HERE_BEFORE_10_6(__negvdi2)
NOT_HERE_BEFORE_10_6(__negvsi2)
NOT_HERE_BEFORE_10_6(__negvti2)
NOT_HERE_BEFORE_10_6(__paritydi2)
NOT_HERE_BEFORE_10_6(__paritysi2)
NOT_HERE_BEFORE_10_6(__parityti2)
NOT_HERE_BEFORE_10_6(__popcountdi2)
NOT_HERE_BEFORE_10_6(__popcountsi2)
NOT_HERE_BEFORE_10_6(__popcountti2)
NOT_HERE_BEFORE_10_6(__powidf2)
NOT_HERE_BEFORE_10_6(__powisf2)
NOT_HERE_BEFORE_10_6(__powitf2)
NOT_HERE_BEFORE_10_6(__powixf2)
NOT_HERE_BEFORE_10_6(__subvdi3)
NOT_HERE_BEFORE_10_6(__subvsi3)
NOT_HERE_BEFORE_10_6(__subvti3)
NOT_HERE_BEFORE_10_6(__ucmpdi2)
NOT_HERE_BEFORE_10_6(__ucmpti2)
NOT_HERE_BEFORE_10_6(__udivdi3)
NOT_HERE_BEFORE_10_6(__udivmoddi4)
NOT_HERE_BEFORE_10_6(__udivmodti4)
NOT_HERE_BEFORE_10_6(__udivti3)
NOT_HERE_BEFORE_10_6(__umoddi3)
NOT_HERE_BEFORE_10_6(__umodti3)
#if __ppc__
NOT_HERE_BEFORE_10_6(__gcc_qadd)
NOT_HERE_BEFORE_10_6(__gcc_qdiv)
NOT_HERE_BEFORE_10_6(__gcc_qmul)
NOT_HERE_BEFORE_10_6(__gcc_qsub)
NOT_HERE_BEFORE_10_6(__trampoline_setup)
#endif /* __ppc__ */
#else /* !__APPLE__ */
extern int avoid_empty_file;
#endif /* !__APPLE__*/

0
lib/arm/CMakeLists.txt Normal file
View File

19
lib/arm/Makefile.mk Normal file
View File

@ -0,0 +1,19 @@
#===- lib/arm/Makefile.mk ----------------------------------*- Makefile -*--===#
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===------------------------------------------------------------------------===#
SubDirs :=
OnlyArchs := armv5 armv6 armv7
AsmSources := $(foreach file,$(wildcard $(Dir)/*.S),$(notdir $(file)))
Sources := $(foreach file,$(wildcard $(Dir)/*.c),$(notdir $(file)))
ObjNames := $(Sources:%.c=%.o) $(AsmSources:%.S=%.o)
Implementation := Optimized
# FIXME: use automatic dependencies?
Dependencies := $(wildcard lib/*.h $(Dir)/*.h)

24
lib/arm/adddf3vfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- adddf3vfp.S - Implement adddf3vfp ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// double __adddf3vfp(double a, double b) { return a + b; }
//
// Adds two double precision floating point numbers using the Darwin
// calling convention where double arguments are passsed in GPR pairs
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__adddf3vfp)
fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6
fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7
faddd d6, d6, d7
fmrrd r0, r1, d6 // move result back to r0/r1 pair
bx lr

24
lib/arm/addsf3vfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- addsf3vfp.S - Implement addsf3vfp ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern float __addsf3vfp(float a, float b);
//
// Adds two single precision floating point numbers using the Darwin
// calling convention where single arguments are passsed in GPRs
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__addsf3vfp)
fmsr s14, r0 // move first param from r0 into float register
fmsr s15, r1 // move second param from r1 into float register
fadds s14, s14, s15
fmrs r0, s14 // move result back to r0
bx lr

36
lib/arm/bswapdi2.S Normal file
View File

@ -0,0 +1,36 @@
//===------- bswapdi2 - Implement bswapdi2 --------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern uint64_t __bswapdi2(uint64_t);
//
// Reverse all the bytes in a 64-bit integer.
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__bswapdi2)
#if __ARM_ARCH_5TEJ__ || __ARM_ARCH_4T__
// before armv6 does not have "rev" instruction
// r2 = rev(r0)
eor r2, r0, r0, ror #16
bic r2, r2, #0xff0000
mov r2, r2, lsr #8
eor r2, r2, r0, ror #8
// r0 = rev(r1)
eor r0, r1, r1, ror #16
bic r0, r0, #0xff0000
mov r0, r0, lsr #8
eor r0, r0, r1, ror #8
#else
rev r2, r0 // r2 = rev(r0)
rev r0, r1 // r0 = rev(r1)
#endif
mov r1, r2 // r1 = r2 = rev(r0)
bx lr

28
lib/arm/bswapsi2.S Normal file
View File

@ -0,0 +1,28 @@
//===------- bswapsi2 - Implement bswapsi2 --------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern uint32_t __bswapsi2(uint32_t);
//
// Reverse all the bytes in a 32-bit integer.
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__bswapsi2)
#if __ARM_ARCH_5TEJ__ || __ARM_ARCH_4T__
// before armv6 does not have "rev" instruction
eor r1, r0, r0, ror #16
bic r1, r1, #0xff0000
mov r1, r1, lsr #8
eor r0, r1, r0, ror #8
#else
rev r0, r0
#endif
bx lr

130
lib/arm/comparesf2.S Normal file
View File

@ -0,0 +1,130 @@
//===-- comparesf2.S - Implement single-precision soft-float comparisons --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the following soft-fp_t comparison routines:
//
// __eqsf2 __gesf2 __unordsf2
// __lesf2 __gtsf2
// __ltsf2
// __nesf2
//
// The semantics of the routines grouped in each column are identical, so there
// is a single implementation for each, with multiple names.
//
// The routines behave as follows:
//
// __lesf2(a,b) returns -1 if a < b
// 0 if a == b
// 1 if a > b
// 1 if either a or b is NaN
//
// __gesf2(a,b) returns -1 if a < b
// 0 if a == b
// 1 if a > b
// -1 if either a or b is NaN
//
// __unordsf2(a,b) returns 0 if both a and b are numbers
// 1 if either a or b is NaN
//
// Note that __lesf2( ) and __gesf2( ) are identical except in their handling of
// NaN values.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
.syntax unified
.align 2
DEFINE_COMPILERRT_FUNCTION(__eqsf2)
DEFINE_COMPILERRT_FUNCTION(__lesf2)
DEFINE_COMPILERRT_FUNCTION(__ltsf2)
DEFINE_COMPILERRT_FUNCTION(__nesf2)
// Make copies of a and b with the sign bit shifted off the top. These will
// be used to detect zeros and NaNs.
mov r2, r0, lsl #1
mov r3, r1, lsl #1
// We do the comparison in three stages (ignoring NaN values for the time
// being). First, we orr the absolute values of a and b; this sets the Z
// flag if both a and b are zero (of either sign). The shift of r3 doesn't
// effect this at all, but it *does* make sure that the C flag is clear for
// the subsequent operations.
orrs r12, r2, r3, lsr #1
// Next, we check if a and b have the same or different signs. If they have
// opposite signs, this eor will set the N flag.
eorsne r12, r0, r1
// If a and b are equal (either both zeros or bit identical; again, we're
// ignoring NaNs for now), this subtract will zero out r0. If they have the
// same sign, the flags are updated as they would be for a comparison of the
// absolute values of a and b.
subspl r0, r2, r3
// If a is smaller in magnitude than b and both have the same sign, place
// the negation of the sign of b in r0. Thus, if both are negative and
// a > b, this sets r0 to 0; if both are positive and a < b, this sets
// r0 to -1.
//
// This is also done if a and b have opposite signs and are not both zero,
// because in that case the subtract was not performed and the C flag is
// still clear from the shift argument in orrs; if a is positive and b
// negative, this places 0 in r0; if a is negative and b positive, -1 is
// placed in r0.
mvnlo r0, r1, asr #31
// If a is greater in magnitude than b and both have the same sign, place
// the sign of b in r0. Thus, if both are negative and a < b, -1 is placed
// in r0, which is the desired result. Conversely, if both are positive
// and a > b, zero is placed in r0.
movhi r0, r1, asr #31
// If you've been keeping track, at this point r0 contains -1 if a < b and
// 0 if a >= b. All that remains to be done is to set it to 1 if a > b.
// If a == b, then the Z flag is set, so we can get the correct final value
// into r0 by simply or'ing with 1 if Z is clear.
orrne r0, r0, #1
// Finally, we need to deal with NaNs. If either argument is NaN, replace
// the value in r0 with 1.
cmp r2, #0xff000000
cmpls r3, #0xff000000
movhi r0, #1
bx lr
.align 2
DEFINE_COMPILERRT_FUNCTION(__gesf2)
DEFINE_COMPILERRT_FUNCTION(__gtsf2)
// Identical to the preceeding except in that we return -1 for NaN values.
// Given that the two paths share so much code, one might be tempted to
// unify them; however, the extra code needed to do so makes the code size
// to performance tradeoff very hard to justify for such small functions.
mov r2, r0, lsl #1
mov r3, r1, lsl #1
orrs r12, r2, r3, lsr #1
eorsne r12, r0, r1
subspl r0, r2, r3
mvnlo r0, r1, asr #31
movhi r0, r1, asr #31
orrne r0, r0, #1
cmp r2, #0xff000000
cmpls r3, #0xff000000
movhi r0, #-1
bx lr
.align 2
DEFINE_COMPILERRT_FUNCTION(__unordsf2)
// Return 1 for NaN values, 0 otherwise.
mov r2, r0, lsl #1
mov r3, r1, lsl #1
mov r0, #0
cmp r2, #0xff000000
cmpls r3, #0xff000000
movhi r0, #1
bx lr

24
lib/arm/divdf3vfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- divdf3vfp.S - Implement divdf3vfp ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern double __divdf3vfp(double a, double b);
//
// Divides two double precision floating point numbers using the Darwin
// calling convention where double arguments are passsed in GPR pairs
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__divdf3vfp)
fmdrr d6, r0, r1 // move first param from r0/r1 pair into d6
fmdrr d7, r2, r3 // move second param from r2/r3 pair into d7
fdivd d5, d6, d7
fmrrd r0, r1, d5 // move result back to r0/r1 pair
bx lr

24
lib/arm/divsf3vfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- divsf3vfp.S - Implement divsf3vfp ---------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern float __divsf3vfp(float a, float b);
//
// Divides two single precision floating point numbers using the Darwin
// calling convention where single arguments are passsed like 32-bit ints.
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__divsf3vfp)
fmsr s14, r0 // move first param from r0 into float register
fmsr s15, r1 // move second param from r1 into float register
fdivs s13, s14, s15
fmrs r0, s13 // move result back to r0
bx lr

27
lib/arm/eqdf2vfp.S Normal file
View File

@ -0,0 +1,27 @@
//===-- eqdf2vfp.S - Implement eqdf2vfp -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern int __eqdf2vfp(double a, double b);
//
// Returns one iff a == b and neither is NaN.
// Uses Darwin calling convention where double precision arguments are passsed
// like in GPR pairs.
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__eqdf2vfp)
fmdrr d6, r0, r1 // load r0/r1 pair in double register
fmdrr d7, r2, r3 // load r2/r3 pair in double register
fcmpd d6, d7
fmstat
moveq r0, #1 // set result register to 1 if equal
movne r0, #0
bx lr

28
lib/arm/eqsf2vfp.S Normal file
View File

@ -0,0 +1,28 @@
//===-- eqsf2vfp.S - Implement eqsf2vfp -----------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern int __eqsf2vfp(float a, float b);
//
// Returns one iff a == b and neither is NaN.
// Uses Darwin calling convention where single precision arguments are passsed
// like 32-bit ints
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__eqsf2vfp)
fmsr s14, r0 // move from GPR 0 to float register
fmsr s15, r1 // move from GPR 1 to float register
fcmps s14, s15
fmstat
moveq r0, #1 // set result register to 1 if equal
movne r0, #0
bx lr

24
lib/arm/extendsfdf2vfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- extendsfdf2vfp.S - Implement extendsfdf2vfp -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern double __extendsfdf2vfp(float a);
//
// Converts single precision float to double precision result.
// Uses Darwin calling convention where a single precision parameter is
// passed in a GPR and a double precision result is returned in R0/R1 pair.
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__extendsfdf2vfp)
fmsr s15, r0 // load float register from R0
fcvtds d7, s15 // convert single to double
fmrrd r0, r1, d7 // return result in r0/r1 pair
bx lr

24
lib/arm/fixdfsivfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- fixdfsivfp.S - Implement fixdfsivfp -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern int __fixdfsivfp(double a);
//
// Converts double precision float to a 32-bit int rounding towards zero.
// Uses Darwin calling convention where a double precision parameter is
// passed in GPR register pair.
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__fixdfsivfp)
fmdrr d7, r0, r1 // load double register from R0/R1
ftosizd s15, d7 // convert double to 32-bit int into s15
fmrs r0, s15 // move s15 to result register
bx lr

24
lib/arm/fixsfsivfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- fixsfsivfp.S - Implement fixsfsivfp -----------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern int __fixsfsivfp(float a);
//
// Converts single precision float to a 32-bit int rounding towards zero.
// Uses Darwin calling convention where a single precision parameter is
// passed in a GPR..
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__fixsfsivfp)
fmsr s15, r0 // load float register from R0
ftosizs s15, s15 // convert single to 32-bit int into s15
fmrs r0, s15 // move s15 to result register
bx lr

25
lib/arm/fixunsdfsivfp.S Normal file
View File

@ -0,0 +1,25 @@
//===-- fixunsdfsivfp.S - Implement fixunsdfsivfp -------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern unsigned int __fixunsdfsivfp(double a);
//
// Converts double precision float to a 32-bit unsigned int rounding towards
// zero. All negative values become zero.
// Uses Darwin calling convention where a double precision parameter is
// passed in GPR register pair.
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__fixunsdfsivfp)
fmdrr d7, r0, r1 // load double register from R0/R1
ftouizd s15, d7 // convert double to 32-bit int into s15
fmrs r0, s15 // move s15 to result register
bx lr

25
lib/arm/fixunssfsivfp.S Normal file
View File

@ -0,0 +1,25 @@
//===-- fixunssfsivfp.S - Implement fixunssfsivfp -------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern unsigned int __fixunssfsivfp(float a);
//
// Converts single precision float to a 32-bit unsigned int rounding towards
// zero. All negative values become zero.
// Uses Darwin calling convention where a single precision parameter is
// passed in a GPR..
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__fixunssfsivfp)
fmsr s15, r0 // load float register from R0
ftouizs s15, s15 // convert single to 32-bit unsigned into s15
fmrs r0, s15 // move s15 to result register
bx lr

24
lib/arm/floatsidfvfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- floatsidfvfp.S - Implement floatsidfvfp ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern double __floatsidfvfp(int a);
//
// Converts a 32-bit int to a double precision float.
// Uses Darwin calling convention where a double precision result is
// return in GPR register pair.
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__floatsidfvfp)
fmsr s15, r0 // move int to float register s15
fsitod d7, s15 // convert 32-bit int in s15 to double in d7
fmrrd r0, r1, d7 // move d7 to result register pair r0/r1
bx lr

24
lib/arm/floatsisfvfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- floatsisfvfp.S - Implement floatsisfvfp ---------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern float __floatsisfvfp(int a);
//
// Converts single precision float to a 32-bit int rounding towards zero.
// Uses Darwin calling convention where a single precision result is
// return in a GPR..
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__floatsisfvfp)
fmsr s15, r0 // move int to float register s15
fsitos s15, s15 // convert 32-bit int in s15 to float in s15
fmrs r0, s15 // move s15 to result register
bx lr

24
lib/arm/floatunssidfvfp.S Normal file
View File

@ -0,0 +1,24 @@
//===-- floatunssidfvfp.S - Implement floatunssidfvfp ---------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "../assembly.h"
//
// extern double __floatunssidfvfp(unsigned int a);
//
// Converts a 32-bit int to a double precision float.
// Uses Darwin calling convention where a double precision result is
// return in GPR register pair.
//
.align 2
DEFINE_COMPILERRT_FUNCTION(__floatunssidfvfp)
fmsr s15, r0 // move int to float register s15
fuitod d7, s15 // convert 32-bit int in s15 to double in d7
fmrrd r0, r1, d7 // move d7 to result register pair r0/r1
bx lr

Some files were not shown because too many files have changed in this diff Show More