mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
We may want a prettier representation of floating-point infinities, but "inf.0" is a particularly bad one. Swift SVN r7638
344 lines
7.6 KiB
C++
344 lines
7.6 KiB
C++
//===--- Stubs.cpp - Swift Language ABI Runtime Stubs ---------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Misc stubs for functions which should be in swift.swift, but are difficult
|
|
// or impossible to write in swift at the moment.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include <mach/mach_time.h>
|
|
#include <sys/resource.h>
|
|
#include <sys/errno.h>
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
#include <cstring>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <algorithm>
|
|
#include <sys/stat.h> // stat
|
|
#include <fcntl.h> // open
|
|
#include <unistd.h> // read, close
|
|
#include <dirent.h>
|
|
#include <limits.h>
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
// static func String(v : Int128, radix : Int) -> String
|
|
extern "C"
|
|
unsigned long long
|
|
print_int(char* TmpBuffer, __int64_t buf_len, __int128_t X, uint64_t Radix,
|
|
bool uppercase) {
|
|
assert(Radix != 0 && Radix <= 36 && "Invalid radix for string conversion");
|
|
char *P = TmpBuffer;
|
|
|
|
bool WasNeg = X < 0;
|
|
__uint128_t Y = WasNeg ? -X : X;
|
|
|
|
if (Y == 0) {
|
|
*P++ = '0';
|
|
} else if (Radix == 10) {
|
|
while (Y) {
|
|
*P++ = '0' + char(Y % 10);
|
|
Y /= 10;
|
|
}
|
|
} else {
|
|
unsigned Radix32 = Radix;
|
|
while (Y) {
|
|
*P++ = llvm::hexdigit(Y % Radix32, !uppercase);
|
|
Y /= Radix32;
|
|
}
|
|
}
|
|
|
|
if (WasNeg) *P++ = '-';
|
|
std::reverse(TmpBuffer, P);
|
|
return size_t(P - TmpBuffer);
|
|
}
|
|
|
|
// static func String(v : UInt128, radix : Int) -> String
|
|
extern "C"
|
|
unsigned long long
|
|
print_uint(char* TmpBuffer, __int64_t buf_len, __uint128_t Y, uint64_t Radix,
|
|
bool uppercase) {
|
|
assert(Radix != 0 && Radix <= 36 && "Invalid radix for string conversion");
|
|
char *P = TmpBuffer;
|
|
|
|
if (Y == 0) {
|
|
*P++ = '0';
|
|
} else if (Radix == 10) {
|
|
while (Y) {
|
|
*P++ = '0' + char(Y % 10);
|
|
Y /= 10;
|
|
}
|
|
} else {
|
|
unsigned Radix32 = Radix;
|
|
while (Y) {
|
|
*P++ = llvm::hexdigit(Y % Radix32, !uppercase);
|
|
Y /= Radix32;
|
|
}
|
|
}
|
|
|
|
std::reverse(TmpBuffer, P);
|
|
return size_t(P - TmpBuffer);
|
|
}
|
|
|
|
// static func String(v : Double) -> String
|
|
extern "C"
|
|
unsigned long long
|
|
print_double(char* Buffer, double X) {
|
|
long long i = sprintf(Buffer, "%g", X);
|
|
// Add ".0" to a float that (a) is not in scientific notation, (b) does not
|
|
// already have a fractional part, and (c) is not infinite.
|
|
if (strchr(Buffer, 'e') == nullptr && strchr(Buffer, '.') == nullptr &&
|
|
strchr(Buffer, 'n') == nullptr) {
|
|
Buffer[i++] = '.';
|
|
Buffer[i++] = '0';
|
|
}
|
|
if (i < 0) {
|
|
__builtin_trap();
|
|
}
|
|
return i;
|
|
}
|
|
|
|
// FIXME: We shouldn't be writing implemenetations for functions in the swift
|
|
// module in C, and this isn't really an ideal place to put those
|
|
// implementations.
|
|
extern "C" void _TSs5printFT3valSi_T_(int64_t l) {
|
|
printf("%lld", l);
|
|
}
|
|
|
|
extern "C" void _TSs5printFT3valSu_T_(uint64_t l) {
|
|
printf("%llu", l);
|
|
}
|
|
|
|
extern "C" void _TSs5printFT3valSd_T_(double l) {
|
|
char Buffer[256];
|
|
unsigned long long i = print_double(Buffer, l);
|
|
Buffer[i] = '\0';
|
|
printf("%s", Buffer);
|
|
}
|
|
|
|
extern "C" bool _TSb13getLogicValuefRSbFT_Bi1_(bool* b) {
|
|
return *b;
|
|
}
|
|
|
|
extern "C" bool swift_getBool(bool b) {
|
|
return b;
|
|
}
|
|
|
|
static bool
|
|
_swift_replOutputIsUTF8(void) {
|
|
const char *lang = getenv("LANG");
|
|
return lang && strstr(lang, "UTF-8");
|
|
}
|
|
|
|
extern "C"
|
|
uint32_t
|
|
swift_replOutputIsUTF8(void) {
|
|
static auto rval = _swift_replOutputIsUTF8();
|
|
return rval;
|
|
}
|
|
|
|
#if defined(__i386__) || defined(__x86_64__)
|
|
static inline uint64_t
|
|
rdtsc() {
|
|
uint32_t lo, hi;
|
|
asm("rdtsc" : "=a" (lo), "=d" (hi));
|
|
return uint64_t(hi) << 32 | lo;
|
|
}
|
|
#else
|
|
#error "not supported"
|
|
#endif
|
|
|
|
static double interruptOverhead;
|
|
static double loopOverhead;
|
|
|
|
static uint64_t
|
|
_swift_startBenchmark(void) {
|
|
return rdtsc();
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
swift_printBenchmark(uint64_t start, uint64_t laps, char *buffer, int64_t len) {
|
|
double val = rdtsc() - start;
|
|
val /= laps;
|
|
val /= interruptOverhead;
|
|
val -= loopOverhead;
|
|
printf("%12.2f %*s\n", val, (int)len, buffer);
|
|
}
|
|
|
|
extern "C"
|
|
__attribute__((noinline,used))
|
|
__typeof__(&_swift_startBenchmark)
|
|
_swift_initBenchmark() asm("_swift_startBenchmark");
|
|
|
|
__typeof__(&_swift_startBenchmark)
|
|
_swift_initBenchmark() {
|
|
asm(".symbol_resolver _swift_startBenchmark");
|
|
union {
|
|
unsigned reg[4*3];
|
|
char brand[48];
|
|
} u;
|
|
char brand[48];
|
|
char *s2 = u.brand;
|
|
char *s1 = brand;
|
|
unsigned eax, ebx, ecx, edx;
|
|
memset(&u, 0, sizeof(u));
|
|
int r;
|
|
|
|
// Let's not have the OS compete with our CPU time if we can avoid it
|
|
r = setvbuf(stdout, 0, _IOFBF, 0);
|
|
assert(r == 0);
|
|
|
|
// XXX -- There doesn't seem to be an API to figure out the max value
|
|
sched_param schedParam;
|
|
schedParam.sched_priority = 79;
|
|
r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &schedParam);
|
|
assert(r == 0);
|
|
|
|
eax = 0x80000002;
|
|
asm("cpuid" : "+a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx));
|
|
u.reg[0] = eax;
|
|
u.reg[1] = ebx;
|
|
u.reg[2] = ecx;
|
|
u.reg[3] = edx;
|
|
|
|
eax = 0x80000003;
|
|
asm("cpuid" : "+a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx));
|
|
u.reg[4] = eax;
|
|
u.reg[5] = ebx;
|
|
u.reg[6] = ecx;
|
|
u.reg[7] = edx;
|
|
|
|
eax = 0x80000004;
|
|
asm("cpuid" : "+a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx));
|
|
u.reg[8] = eax;
|
|
u.reg[9] = ebx;
|
|
u.reg[10] = ecx;
|
|
u.reg[11] = edx;
|
|
|
|
while (*s2 == ' ') {
|
|
s2++;
|
|
}
|
|
do {
|
|
while (s2[0] == ' ' && s2[1] == ' ') {
|
|
s2++;
|
|
}
|
|
} while ((*s1++ = *s2++));
|
|
printf("Processor: %s\n\n", brand);
|
|
|
|
uint64_t start = rdtsc();
|
|
for (unsigned long i = 0; i < 1000000000ull; i++) {
|
|
asm("");
|
|
}
|
|
double delta = (rdtsc() - start) / 1000000000.0;
|
|
assert((delta >= 1.0 && delta < 1.05) || (delta >= 2.0 && delta < 2.05));
|
|
if (delta >= 2.0) {
|
|
loopOverhead = 2.0;
|
|
interruptOverhead = delta / 2.0;
|
|
} else {
|
|
loopOverhead = 1.0;
|
|
interruptOverhead = delta / 1.0;
|
|
}
|
|
assert((interruptOverhead - 1.0) < 0.01);
|
|
|
|
eax = 6;
|
|
asm("cpuid" : "+a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx));
|
|
|
|
if (eax & 2) {
|
|
fprintf(stderr, "WARNING: TurboBoost. Results will be less reliable.\n");
|
|
fprintf(stderr, " Consider: sudo /usr/local/bin/pstates -D\n\n");
|
|
}
|
|
|
|
if (geteuid()) {
|
|
fprintf(stderr, "WARNING: Non-elevated priority. Results will be less reliable.\n");
|
|
fprintf(stderr, " Consider: sudo ./myBench\n\n");
|
|
}
|
|
|
|
return _swift_startBenchmark;
|
|
}
|
|
|
|
extern "C"
|
|
int
|
|
swift_file_open(const char* filename)
|
|
{
|
|
return open(filename, O_RDONLY);
|
|
}
|
|
|
|
extern "C"
|
|
int
|
|
swift_file_close(int fd)
|
|
{
|
|
return close(fd);
|
|
}
|
|
|
|
extern "C"
|
|
size_t
|
|
swift_file_read(int fd, char* buf, size_t nb)
|
|
{
|
|
return read(fd, buf, nb);
|
|
}
|
|
|
|
extern "C"
|
|
size_t
|
|
swift_fd_size(int fd)
|
|
{
|
|
struct stat buf;
|
|
int err = fstat(fd, &buf);
|
|
assert(err == 0);
|
|
(void) err;
|
|
return buf.st_size;
|
|
}
|
|
|
|
struct readdir_tuple_s {
|
|
char *str;
|
|
int64_t len;
|
|
};
|
|
|
|
extern "C"
|
|
struct readdir_tuple_s
|
|
posix_readdir_hack(DIR *d)
|
|
{
|
|
struct readdir_tuple_s rval = { NULL, 0 };
|
|
struct dirent *dp;
|
|
if ((dp = readdir(d))) {
|
|
rval.str = dp->d_name;
|
|
rval.len = dp->d_namlen;
|
|
}
|
|
return rval;
|
|
}
|
|
|
|
extern "C"
|
|
int64_t
|
|
posix_isDirectory_hack(const char *path)
|
|
{
|
|
struct stat sb;
|
|
int r = stat(path, &sb);
|
|
(void)r;
|
|
assert(r != -1);
|
|
return S_ISDIR(sb.st_mode);
|
|
}
|
|
|
|
extern "C"
|
|
int
|
|
posix_get_errno(void)
|
|
{
|
|
return errno; // errno is not a global, but a macro
|
|
}
|
|
|
|
extern "C"
|
|
void
|
|
posix_set_errno(int value)
|
|
{
|
|
errno = value; // errno is not a global, but a macro
|
|
}
|