mirror of
https://github.com/corda/corda.git
synced 2025-01-23 21:08:48 +00:00
Merge branch 'master' of oss.readytalk.com:/var/local/git/avian
This commit is contained in:
commit
1f98cc633d
@ -361,10 +361,9 @@ class Assembler {
|
|||||||
unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask) = 0;
|
unsigned bSize, uint8_t* bTypeMask, uint64_t* bRegisterMask) = 0;
|
||||||
|
|
||||||
virtual void planMove
|
virtual void planMove
|
||||||
(unsigned size,
|
(unsigned size, uint8_t* srcTypeMask, uint64_t* srcRegisterMask,
|
||||||
uint8_t srcTypeMask, uint64_t srcRegisterMask,
|
uint8_t* tmpTypeMask, uint64_t* tmpRegisterMask,
|
||||||
uint8_t dstTypeMask, uint64_t dstRegisterMask,
|
uint8_t dstTypeMask, uint64_t dstRegisterMask) = 0;
|
||||||
uint8_t* tmpTypeMask, uint64_t* tmpRegisterMask) = 0;
|
|
||||||
|
|
||||||
virtual void planSource
|
virtual void planSource
|
||||||
(TernaryOperation op,
|
(TernaryOperation op,
|
||||||
|
@ -235,7 +235,7 @@ methodForIp(MyThread* t, void* ip)
|
|||||||
// we must use a version of the method tree at least as recent as the
|
// we must use a version of the method tree at least as recent as the
|
||||||
// compiled form of the method containing the specified address (see
|
// compiled form of the method containing the specified address (see
|
||||||
// compile(MyThread*, Allocator*, BootContext*, object)):
|
// compile(MyThread*, Allocator*, BootContext*, object)):
|
||||||
memoryBarrier();
|
loadMemoryBarrier();
|
||||||
|
|
||||||
return treeQuery(t, methodTree(t), reinterpret_cast<intptr_t>(ip),
|
return treeQuery(t, methodTree(t), reinterpret_cast<intptr_t>(ip),
|
||||||
methodTreeSentinal(t), compareIpToMethodBounds);
|
methodTreeSentinal(t), compareIpToMethodBounds);
|
||||||
@ -785,6 +785,10 @@ class Context {
|
|||||||
{
|
{
|
||||||
if (size == 8) {
|
if (size == 8) {
|
||||||
switch(op) {
|
switch(op) {
|
||||||
|
case Absolute:
|
||||||
|
assert(t, resultSize == 8);
|
||||||
|
return local::getThunk(t, absoluteLongThunk);
|
||||||
|
|
||||||
case FloatNegate:
|
case FloatNegate:
|
||||||
assert(t, resultSize == 8);
|
assert(t, resultSize == 8);
|
||||||
return local::getThunk(t, negateDoubleThunk);
|
return local::getThunk(t, negateDoubleThunk);
|
||||||
@ -819,12 +823,16 @@ class Context {
|
|||||||
assert(t, size == 4);
|
assert(t, size == 4);
|
||||||
|
|
||||||
switch(op) {
|
switch(op) {
|
||||||
|
case Absolute:
|
||||||
|
assert(t, resultSize == 4);
|
||||||
|
return local::getThunk(t, absoluteIntThunk);
|
||||||
|
|
||||||
case FloatNegate:
|
case FloatNegate:
|
||||||
assert(t, size == 4);
|
assert(t, resultSize == 4);
|
||||||
return local::getThunk(t, negateFloatThunk);
|
return local::getThunk(t, negateFloatThunk);
|
||||||
|
|
||||||
case FloatAbsolute:
|
case FloatAbsolute:
|
||||||
assert(t, size == 4);
|
assert(t, resultSize == 4);
|
||||||
return local::getThunk(t, absoluteFloatThunk);
|
return local::getThunk(t, absoluteFloatThunk);
|
||||||
|
|
||||||
case Float2Float:
|
case Float2Float:
|
||||||
@ -2160,6 +2168,18 @@ absoluteFloat(uint32_t a)
|
|||||||
return floatToBits(fabsf(bitsToFloat(a)));
|
return floatToBits(fabsf(bitsToFloat(a)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
absoluteLong(int64_t a)
|
||||||
|
{
|
||||||
|
return a > 0 ? a : -a;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t
|
||||||
|
absoluteInt(int32_t a)
|
||||||
|
{
|
||||||
|
return a > 0 ? a : -a;
|
||||||
|
}
|
||||||
|
|
||||||
int64_t
|
int64_t
|
||||||
divideLong(int64_t b, int64_t a)
|
divideLong(int64_t b, int64_t a)
|
||||||
{
|
{
|
||||||
@ -2934,7 +2954,7 @@ bool
|
|||||||
intrinsic(MyThread* t, Frame* frame, object target)
|
intrinsic(MyThread* t, Frame* frame, object target)
|
||||||
{
|
{
|
||||||
#define MATCH(name, constant) \
|
#define MATCH(name, constant) \
|
||||||
(byteArrayLength(t, name) - 1 == sizeof(constant) \
|
(byteArrayLength(t, name) == sizeof(constant) \
|
||||||
and strcmp(reinterpret_cast<char*>(&byteArrayBody(t, name, 0)), \
|
and strcmp(reinterpret_cast<char*>(&byteArrayBody(t, name, 0)), \
|
||||||
constant) == 0)
|
constant) == 0)
|
||||||
|
|
||||||
@ -3040,6 +3060,7 @@ compile(MyThread* t, Frame* initialFrame, unsigned ip,
|
|||||||
(4, 4, c->memory
|
(4, 4, c->memory
|
||||||
(array, Compiler::FloatType, ArrayBody, index, 4), BytesPerWord));
|
(array, Compiler::FloatType, ArrayBody, index, 4), BytesPerWord));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case iaload:
|
case iaload:
|
||||||
frame->pushInt
|
frame->pushInt
|
||||||
(c->load
|
(c->load
|
||||||
@ -5621,6 +5642,7 @@ compile(MyThread* t, Allocator* allocator, Context* context)
|
|||||||
frame.set(--index, Frame::Long);
|
frame.set(--index, Frame::Long);
|
||||||
c->initLocal(2, index, Compiler::IntegerType);
|
c->initLocal(2, index, Compiler::IntegerType);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'D':
|
case 'D':
|
||||||
frame.set(--index, Frame::Long);
|
frame.set(--index, Frame::Long);
|
||||||
frame.set(--index, Frame::Long);
|
frame.set(--index, Frame::Long);
|
||||||
@ -5876,7 +5898,7 @@ resolveNative(MyThread* t, object method)
|
|||||||
// methodCompiled, since we don't want them using the slow calling
|
// methodCompiled, since we don't want them using the slow calling
|
||||||
// convention on a function that expects the fast calling
|
// convention on a function that expects the fast calling
|
||||||
// convention:
|
// convention:
|
||||||
memoryBarrier();
|
storeStoreMemoryBarrier();
|
||||||
|
|
||||||
methodCompiled(t, method) = reinterpret_cast<uintptr_t>(function);
|
methodCompiled(t, method) = reinterpret_cast<uintptr_t>(function);
|
||||||
}
|
}
|
||||||
@ -7467,7 +7489,7 @@ findCallNode(MyThread* t, void* address)
|
|||||||
// we must use a version of the call table at least as recent as the
|
// we must use a version of the call table at least as recent as the
|
||||||
// compiled form of the method containing the specified address (see
|
// compiled form of the method containing the specified address (see
|
||||||
// compile(MyThread*, Allocator*, BootContext*, object)):
|
// compile(MyThread*, Allocator*, BootContext*, object)):
|
||||||
memoryBarrier();
|
loadMemoryBarrier();
|
||||||
|
|
||||||
MyProcessor* p = processor(t);
|
MyProcessor* p = processor(t);
|
||||||
object table = p->callTable;
|
object table = p->callTable;
|
||||||
@ -8227,7 +8249,7 @@ compile(MyThread* t, Allocator* allocator, BootContext* bootContext,
|
|||||||
reinterpret_cast<intptr_t>(compiled), clone, methodTreeSentinal(t),
|
reinterpret_cast<intptr_t>(compiled), clone, methodTreeSentinal(t),
|
||||||
compareIpToMethodBounds);
|
compareIpToMethodBounds);
|
||||||
|
|
||||||
memoryBarrier();
|
storeStoreMemoryBarrier();
|
||||||
|
|
||||||
methodCompiled(t, method) = reinterpret_cast<intptr_t>(compiled);
|
methodCompiled(t, method) = reinterpret_cast<intptr_t>(compiled);
|
||||||
|
|
||||||
|
868
src/compiler.cpp
868
src/compiler.cpp
File diff suppressed because it is too large
Load Diff
@ -76,7 +76,10 @@ markBitAtomic(uintptr_t* map, unsigned i)
|
|||||||
{
|
{
|
||||||
uintptr_t* p = map + wordOf(i);
|
uintptr_t* p = map + wordOf(i);
|
||||||
uintptr_t v = static_cast<uintptr_t>(1) << bitOf(i);
|
uintptr_t v = static_cast<uintptr_t>(1) << bitOf(i);
|
||||||
while (not atomicCompareAndSwap(p, *p, *p | v)) { }
|
for (uintptr_t old = *p;
|
||||||
|
not atomicCompareAndSwap(p, old, old | v);
|
||||||
|
old = *p)
|
||||||
|
{ }
|
||||||
}
|
}
|
||||||
#endif // USE_ATOMIC_OPERATIONS
|
#endif // USE_ATOMIC_OPERATIONS
|
||||||
|
|
||||||
|
@ -2173,10 +2173,7 @@ JNI_CreateJavaVM(Machine** m, Thread** t, void* args)
|
|||||||
System* s = makeSystem(crashDumpDirectory);
|
System* s = makeSystem(crashDumpDirectory);
|
||||||
Heap* h = makeHeap(s, heapLimit);
|
Heap* h = makeHeap(s, heapLimit);
|
||||||
Finder* f = makeFinder(s, RUNTIME_ARRAY_BODY(classpathBuffer), bootLibrary);
|
Finder* f = makeFinder(s, RUNTIME_ARRAY_BODY(classpathBuffer), bootLibrary);
|
||||||
Processor* p = makeProcessor(s, h, false); // change back to true
|
Processor* p = makeProcessor(s, h, true);
|
||||||
// once use of SSE is
|
|
||||||
// fixed on 32-bit
|
|
||||||
// systems
|
|
||||||
|
|
||||||
const char** properties = static_cast<const char**>
|
const char** properties = static_cast<const char**>
|
||||||
(h->allocate(sizeof(const char*) * propertyCount));
|
(h->allocate(sizeof(const char*) * propertyCount));
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "constants.h"
|
#include "constants.h"
|
||||||
#include "processor.h"
|
#include "processor.h"
|
||||||
|
#include "arch.h"
|
||||||
|
|
||||||
using namespace vm;
|
using namespace vm;
|
||||||
|
|
||||||
@ -21,6 +22,17 @@ namespace {
|
|||||||
|
|
||||||
const unsigned NoByte = 0xFFFF;
|
const unsigned NoByte = 0xFFFF;
|
||||||
|
|
||||||
|
#ifdef USE_ATOMIC_OPERATIONS
|
||||||
|
void
|
||||||
|
atomicIncrement(uint32_t* p, int v)
|
||||||
|
{
|
||||||
|
for (uint32_t old = *p;
|
||||||
|
not atomicCompareAndSwap32(p, old, old + v);
|
||||||
|
old = *p)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool
|
bool
|
||||||
find(Thread* t, Thread* o)
|
find(Thread* t, Thread* o)
|
||||||
{
|
{
|
||||||
@ -2319,20 +2331,33 @@ enter(Thread* t, Thread::State s)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef USE_ATOMIC_OPERATIONS
|
||||||
|
# define INCREMENT atomicIncrement
|
||||||
|
# define ACQUIRE_LOCK ACQUIRE_RAW(t, t->m->stateLock)
|
||||||
|
# define STORE_LOAD_MEMORY_BARRIER storeLoadMemoryBarrier()
|
||||||
|
#else
|
||||||
|
# define INCREMENT(pointer, value) *(pointer) += value;
|
||||||
|
# define ACQUIRE_LOCK
|
||||||
|
# define STORE_LOAD_MEMORY_BARRIER
|
||||||
|
|
||||||
ACQUIRE_RAW(t, t->m->stateLock);
|
ACQUIRE_RAW(t, t->m->stateLock);
|
||||||
|
#endif // not USE_ATOMIC_OPERATIONS
|
||||||
|
|
||||||
switch (s) {
|
switch (s) {
|
||||||
case Thread::ExclusiveState: {
|
case Thread::ExclusiveState: {
|
||||||
|
ACQUIRE_LOCK;
|
||||||
|
|
||||||
while (t->m->exclusive) {
|
while (t->m->exclusive) {
|
||||||
// another thread got here first.
|
// another thread got here first.
|
||||||
ENTER(t, Thread::IdleState);
|
ENTER(t, Thread::IdleState);
|
||||||
|
t->m->stateLock->wait(t->systemThread, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (t->state) {
|
switch (t->state) {
|
||||||
case Thread::ActiveState: break;
|
case Thread::ActiveState: break;
|
||||||
|
|
||||||
case Thread::IdleState: {
|
case Thread::IdleState: {
|
||||||
++ t->m->activeCount;
|
INCREMENT(&(t->m->activeCount), 1);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: abort(t);
|
default: abort(t);
|
||||||
@ -2341,13 +2366,34 @@ enter(Thread* t, Thread::State s)
|
|||||||
t->state = Thread::ExclusiveState;
|
t->state = Thread::ExclusiveState;
|
||||||
t->m->exclusive = t;
|
t->m->exclusive = t;
|
||||||
|
|
||||||
|
STORE_LOAD_MEMORY_BARRIER;
|
||||||
|
|
||||||
while (t->m->activeCount > 1) {
|
while (t->m->activeCount > 1) {
|
||||||
t->m->stateLock->wait(t->systemThread, 0);
|
t->m->stateLock->wait(t->systemThread, 0);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Thread::IdleState:
|
case Thread::IdleState:
|
||||||
|
if (t->state == Thread::ActiveState) {
|
||||||
|
// fast path
|
||||||
|
assert(t, t->m->activeCount > 0);
|
||||||
|
INCREMENT(&(t->m->activeCount), -1);
|
||||||
|
|
||||||
|
t->state = s;
|
||||||
|
|
||||||
|
if (t->m->exclusive) {
|
||||||
|
ACQUIRE_LOCK;
|
||||||
|
|
||||||
|
t->m->stateLock->notifyAll(t->systemThread);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// fall through to slow path
|
||||||
|
}
|
||||||
|
|
||||||
case Thread::ZombieState: {
|
case Thread::ZombieState: {
|
||||||
|
ACQUIRE_LOCK;
|
||||||
|
|
||||||
switch (t->state) {
|
switch (t->state) {
|
||||||
case Thread::ExclusiveState: {
|
case Thread::ExclusiveState: {
|
||||||
assert(t, t->m->exclusive == t);
|
assert(t, t->m->exclusive == t);
|
||||||
@ -2360,7 +2406,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(t, t->m->activeCount > 0);
|
assert(t, t->m->activeCount > 0);
|
||||||
-- t->m->activeCount;
|
INCREMENT(&(t->m->activeCount), -1);
|
||||||
|
|
||||||
if (s == Thread::ZombieState) {
|
if (s == Thread::ZombieState) {
|
||||||
assert(t, t->m->liveCount > 0);
|
assert(t, t->m->liveCount > 0);
|
||||||
@ -2375,7 +2421,24 @@ enter(Thread* t, Thread::State s)
|
|||||||
t->m->stateLock->notifyAll(t->systemThread);
|
t->m->stateLock->notifyAll(t->systemThread);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Thread::ActiveState: {
|
case Thread::ActiveState:
|
||||||
|
if (t->state == Thread::IdleState and t->m->exclusive == 0) {
|
||||||
|
// fast path
|
||||||
|
INCREMENT(&(t->m->activeCount), 1);
|
||||||
|
|
||||||
|
t->state = s;
|
||||||
|
|
||||||
|
if (t->m->exclusive) {
|
||||||
|
// another thread has entered the exclusive state, so we
|
||||||
|
// return to idle and use the slow path to become active
|
||||||
|
enter(t, Thread::IdleState);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ ACQUIRE_LOCK;
|
||||||
|
|
||||||
switch (t->state) {
|
switch (t->state) {
|
||||||
case Thread::ExclusiveState: {
|
case Thread::ExclusiveState: {
|
||||||
assert(t, t->m->exclusive == t);
|
assert(t, t->m->exclusive == t);
|
||||||
@ -2392,7 +2455,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
t->m->stateLock->wait(t->systemThread, 0);
|
t->m->stateLock->wait(t->systemThread, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
++ t->m->activeCount;
|
INCREMENT(&(t->m->activeCount), 1);
|
||||||
if (t->state == Thread::NoState) {
|
if (t->state == Thread::NoState) {
|
||||||
++ t->m->liveCount;
|
++ t->m->liveCount;
|
||||||
}
|
}
|
||||||
@ -2404,6 +2467,8 @@ enter(Thread* t, Thread::State s)
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case Thread::ExitState: {
|
case Thread::ExitState: {
|
||||||
|
ACQUIRE_LOCK;
|
||||||
|
|
||||||
switch (t->state) {
|
switch (t->state) {
|
||||||
case Thread::ExclusiveState: {
|
case Thread::ExclusiveState: {
|
||||||
assert(t, t->m->exclusive == t);
|
assert(t, t->m->exclusive == t);
|
||||||
@ -2418,7 +2483,7 @@ enter(Thread* t, Thread::State s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(t, t->m->activeCount > 0);
|
assert(t, t->m->activeCount > 0);
|
||||||
-- t->m->activeCount;
|
INCREMENT(&(t->m->activeCount), -1);
|
||||||
|
|
||||||
t->state = s;
|
t->state = s;
|
||||||
|
|
||||||
|
@ -2065,6 +2065,9 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
*aTypeMask = (1 << RegisterOperand);
|
*aTypeMask = (1 << RegisterOperand);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Absolute:
|
||||||
|
case FloatAbsolute:
|
||||||
|
case FloatSquareRoot:
|
||||||
case FloatNegate:
|
case FloatNegate:
|
||||||
case Float2Float:
|
case Float2Float:
|
||||||
case Float2Int:
|
case Float2Int:
|
||||||
@ -2096,19 +2099,20 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void planMove
|
virtual void planMove
|
||||||
(unsigned,
|
(unsigned, uint8_t* srcTypeMask, uint64_t* srcRegisterMask,
|
||||||
uint8_t srcTypeMask, uint64_t srcRegisterMask,
|
uint8_t* tmpTypeMask, uint64_t* tmpRegisterMask,
|
||||||
uint8_t dstTypeMask, uint64_t,
|
uint8_t dstTypeMask, uint64_t)
|
||||||
uint8_t* tmpTypeMask, uint64_t* tmpRegisterMask)
|
|
||||||
{
|
{
|
||||||
*tmpTypeMask = srcTypeMask;
|
*srcTypeMask = ~0;
|
||||||
*tmpRegisterMask = srcRegisterMask;
|
*srcRegisterMask = ~static_cast<uint64_t>(0);
|
||||||
|
|
||||||
if ((dstTypeMask & (1 << MemoryOperand))
|
*tmpTypeMask = 0;
|
||||||
and (srcTypeMask & ((1 << MemoryOperand) | 1 << AddressOperand)))
|
*tmpRegisterMask = 0;
|
||||||
{
|
|
||||||
// can't move directly from memory to memory
|
if (dstTypeMask & (1 << MemoryOperand)) {
|
||||||
*tmpTypeMask = (1 << RegisterOperand);
|
// can't move directly from memory or constant to memory
|
||||||
|
*srcTypeMask = 1 << RegisterOperand;
|
||||||
|
*tmpTypeMask = 1 << RegisterOperand;
|
||||||
*tmpRegisterMask = ~static_cast<uint64_t>(0);
|
*tmpRegisterMask = ~static_cast<uint64_t>(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,7 +92,7 @@ syncInstructionCache(const void* start, unsigned size)
|
|||||||
|
|
||||||
#ifdef USE_ATOMIC_OPERATIONS
|
#ifdef USE_ATOMIC_OPERATIONS
|
||||||
inline bool
|
inline bool
|
||||||
atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
|
atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_)
|
||||||
{
|
{
|
||||||
#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1)
|
#if (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1)
|
||||||
return __sync_bool_compare_and_swap(p, old, new_);
|
return __sync_bool_compare_and_swap(p, old, new_);
|
||||||
@ -118,6 +118,12 @@ atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
|
|||||||
return result;
|
return result;
|
||||||
#endif // not GCC >= 4.1
|
#endif // not GCC >= 4.1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
|
||||||
|
{
|
||||||
|
return atomicCompareAndSwap32(reinterpret_cast<uint32_t*>(p), old, new_);
|
||||||
|
}
|
||||||
#endif // USE_ATOMIC_OPERATIONS
|
#endif // USE_ATOMIC_OPERATIONS
|
||||||
|
|
||||||
inline uint64_t
|
inline uint64_t
|
||||||
|
@ -22,6 +22,8 @@ THUNK(divideFloat)
|
|||||||
THUNK(moduloFloat)
|
THUNK(moduloFloat)
|
||||||
THUNK(negateFloat)
|
THUNK(negateFloat)
|
||||||
THUNK(absoluteFloat)
|
THUNK(absoluteFloat)
|
||||||
|
THUNK(absoluteLong)
|
||||||
|
THUNK(absoluteInt)
|
||||||
THUNK(divideLong)
|
THUNK(divideLong)
|
||||||
THUNK(divideInt)
|
THUNK(divideInt)
|
||||||
THUNK(moduloLong)
|
THUNK(moduloLong)
|
||||||
|
143
src/x86.cpp
143
src/x86.cpp
@ -113,23 +113,7 @@ class MyBlock: public Assembler::Block {
|
|||||||
unsigned size;
|
unsigned size;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Context {
|
class Context;
|
||||||
public:
|
|
||||||
Context(System* s, Allocator* a, Zone* zone):
|
|
||||||
s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0),
|
|
||||||
firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)),
|
|
||||||
lastBlock(firstBlock)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
System* s;
|
|
||||||
Zone* zone;
|
|
||||||
Assembler::Client* client;
|
|
||||||
Vector code;
|
|
||||||
Task* tasks;
|
|
||||||
uint8_t* result;
|
|
||||||
MyBlock* firstBlock;
|
|
||||||
MyBlock* lastBlock;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef void (*OperationType)(Context*);
|
typedef void (*OperationType)(Context*);
|
||||||
|
|
||||||
@ -163,6 +147,25 @@ class ArchitectureContext {
|
|||||||
* OperandTypeCount];
|
* OperandTypeCount];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Context {
|
||||||
|
public:
|
||||||
|
Context(System* s, Allocator* a, Zone* zone, ArchitectureContext* ac):
|
||||||
|
s(s), zone(zone), client(0), code(s, a, 1024), tasks(0), result(0),
|
||||||
|
firstBlock(new (zone->allocate(sizeof(MyBlock))) MyBlock(0)),
|
||||||
|
lastBlock(firstBlock), ac(ac)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
System* s;
|
||||||
|
Zone* zone;
|
||||||
|
Assembler::Client* client;
|
||||||
|
Vector code;
|
||||||
|
Task* tasks;
|
||||||
|
uint8_t* result;
|
||||||
|
MyBlock* firstBlock;
|
||||||
|
MyBlock* lastBlock;
|
||||||
|
ArchitectureContext* ac;
|
||||||
|
};
|
||||||
|
|
||||||
void NO_RETURN
|
void NO_RETURN
|
||||||
abort(Context* c)
|
abort(Context* c)
|
||||||
{
|
{
|
||||||
@ -620,6 +623,27 @@ void
|
|||||||
ignore(Context*)
|
ignore(Context*)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
|
void
|
||||||
|
storeLoadBarrier(Context* c)
|
||||||
|
{
|
||||||
|
if (useSSE(c->ac)) {
|
||||||
|
// mfence:
|
||||||
|
c->code.append(0x0f);
|
||||||
|
c->code.append(0xae);
|
||||||
|
c->code.append(0xf0);
|
||||||
|
} else {
|
||||||
|
// lock addq $0x0,(%rsp):
|
||||||
|
c->code.append(0xf0);
|
||||||
|
if (BytesPerWord == 8) {
|
||||||
|
c->code.append(0x48);
|
||||||
|
}
|
||||||
|
c->code.append(0x83);
|
||||||
|
c->code.append(0x04);
|
||||||
|
c->code.append(0x24);
|
||||||
|
c->code.append(0x00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
unconditional(Context* c, unsigned jump, Assembler::Constant* a)
|
unconditional(Context* c, unsigned jump, Assembler::Constant* a)
|
||||||
{
|
{
|
||||||
@ -946,17 +970,20 @@ void
|
|||||||
sseMoveRR(Context* c, unsigned aSize, Assembler::Register* a,
|
sseMoveRR(Context* c, unsigned aSize, Assembler::Register* a,
|
||||||
unsigned bSize UNUSED, Assembler::Register* b)
|
unsigned bSize UNUSED, Assembler::Register* b)
|
||||||
{
|
{
|
||||||
|
assert(c, aSize >= 4);
|
||||||
|
assert(c, aSize == bSize);
|
||||||
|
|
||||||
if (floatReg(a) and floatReg(b)) {
|
if (floatReg(a) and floatReg(b)) {
|
||||||
if (aSize == 4) {
|
if (aSize == 4) {
|
||||||
opcode(c, 0xf3);
|
opcode(c, 0xf3);
|
||||||
maybeRex(c, 4, a, b);
|
maybeRex(c, 4, a, b);
|
||||||
opcode(c, 0x0f, 0x10);
|
opcode(c, 0x0f, 0x10);
|
||||||
modrm(c, 0xc0, b, a);
|
modrm(c, 0xc0, a, b);
|
||||||
} else {
|
} else {
|
||||||
opcode(c, 0xf2);
|
opcode(c, 0xf2);
|
||||||
maybeRex(c, 4, a, b);
|
maybeRex(c, 8, a, b);
|
||||||
opcode(c, 0x0f, 0x10);
|
opcode(c, 0x0f, 0x10);
|
||||||
modrm(c, 0xc0, b, a);
|
modrm(c, 0xc0, a, b);
|
||||||
}
|
}
|
||||||
} else if (floatReg(a)) {
|
} else if (floatReg(a)) {
|
||||||
opcode(c, 0x66);
|
opcode(c, 0x66);
|
||||||
@ -1090,6 +1117,8 @@ void
|
|||||||
sseMoveMR(Context* c, unsigned aSize, Assembler::Memory* a,
|
sseMoveMR(Context* c, unsigned aSize, Assembler::Memory* a,
|
||||||
unsigned bSize UNUSED, Assembler::Register* b)
|
unsigned bSize UNUSED, Assembler::Register* b)
|
||||||
{
|
{
|
||||||
|
assert(c, aSize >= 4);
|
||||||
|
|
||||||
if (BytesPerWord == 4 and aSize == 8) {
|
if (BytesPerWord == 4 and aSize == 8) {
|
||||||
opcode(c, 0xf3);
|
opcode(c, 0xf3);
|
||||||
opcode(c, 0x0f, 0x7e);
|
opcode(c, 0x0f, 0x7e);
|
||||||
@ -1165,6 +1194,7 @@ void
|
|||||||
sseMoveRM(Context* c, unsigned aSize, Assembler::Register* a,
|
sseMoveRM(Context* c, unsigned aSize, Assembler::Register* a,
|
||||||
UNUSED unsigned bSize, Assembler::Memory* b)
|
UNUSED unsigned bSize, Assembler::Memory* b)
|
||||||
{
|
{
|
||||||
|
assert(c, aSize >= 4);
|
||||||
assert(c, aSize == bSize);
|
assert(c, aSize == bSize);
|
||||||
|
|
||||||
if (BytesPerWord == 4 and aSize == 8) {
|
if (BytesPerWord == 4 and aSize == 8) {
|
||||||
@ -2496,7 +2526,7 @@ populateTables(ArchitectureContext* c)
|
|||||||
zo[Return] = return_;
|
zo[Return] = return_;
|
||||||
zo[LoadBarrier] = ignore;
|
zo[LoadBarrier] = ignore;
|
||||||
zo[StoreStoreBarrier] = ignore;
|
zo[StoreStoreBarrier] = ignore;
|
||||||
zo[StoreLoadBarrier] = ignore;
|
zo[StoreLoadBarrier] = storeLoadBarrier;
|
||||||
|
|
||||||
uo[index(c, Call, C)] = CAST1(callC);
|
uo[index(c, Call, C)] = CAST1(callC);
|
||||||
uo[index(c, Call, R)] = CAST1(callR);
|
uo[index(c, Call, R)] = CAST1(callR);
|
||||||
@ -2889,9 +2919,13 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FloatAbsolute:
|
case FloatAbsolute:
|
||||||
|
if (useSSE(&c)) {
|
||||||
*aTypeMask = (1 << RegisterOperand);
|
*aTypeMask = (1 << RegisterOperand);
|
||||||
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
|
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
|
||||||
| FloatRegisterMask;
|
| FloatRegisterMask;
|
||||||
|
} else {
|
||||||
|
*thunk = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FloatNegate:
|
case FloatNegate:
|
||||||
@ -2905,9 +2939,13 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case FloatSquareRoot:
|
case FloatSquareRoot:
|
||||||
|
if (useSSE(&c)) {
|
||||||
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
||||||
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
|
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
|
||||||
| FloatRegisterMask;
|
| FloatRegisterMask;
|
||||||
|
} else {
|
||||||
|
*thunk = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Float2Float:
|
case Float2Float:
|
||||||
@ -2921,7 +2959,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Float2Int:
|
case Float2Int:
|
||||||
if (useSSE(&c) and (bSize <= BytesPerWord)) {
|
if (useSSE(&c) and bSize <= BytesPerWord) {
|
||||||
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
||||||
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
|
*aRegisterMask = (static_cast<uint64_t>(FloatRegisterMask) << 32)
|
||||||
| FloatRegisterMask;
|
| FloatRegisterMask;
|
||||||
@ -2931,7 +2969,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Int2Float:
|
case Int2Float:
|
||||||
if (useSSE(&c) and (aSize <= BytesPerWord)) {
|
if (useSSE(&c) and aSize <= BytesPerWord) {
|
||||||
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
||||||
*aRegisterMask = GeneralRegisterMask
|
*aRegisterMask = GeneralRegisterMask
|
||||||
| (static_cast<uint64_t>(GeneralRegisterMask) << 32);
|
| (static_cast<uint64_t>(GeneralRegisterMask) << 32);
|
||||||
@ -2941,9 +2979,8 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Move:
|
case Move:
|
||||||
*aTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
*aTypeMask = ~0;
|
||||||
*aRegisterMask = GeneralRegisterMask
|
*aRegisterMask = ~static_cast<uint64_t>(0);
|
||||||
| (static_cast<uint64_t>(GeneralRegisterMask) << 32);
|
|
||||||
|
|
||||||
if (BytesPerWord == 4) {
|
if (BytesPerWord == 4) {
|
||||||
if (aSize == 4 and bSize == 8) {
|
if (aSize == 4 and bSize == 8) {
|
||||||
@ -3039,38 +3076,46 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual void planMove
|
virtual void planMove
|
||||||
(unsigned size,
|
(unsigned size, uint8_t* srcTypeMask, uint64_t* srcRegisterMask,
|
||||||
uint8_t srcTypeMask, uint64_t srcRegisterMask,
|
uint8_t* tmpTypeMask, uint64_t* tmpRegisterMask,
|
||||||
uint8_t dstTypeMask, uint64_t dstRegisterMask,
|
uint8_t dstTypeMask, uint64_t dstRegisterMask)
|
||||||
uint8_t* tmpTypeMask, uint64_t* tmpRegisterMask)
|
|
||||||
{
|
{
|
||||||
*tmpTypeMask = srcTypeMask;
|
*srcTypeMask = ~0;
|
||||||
*tmpRegisterMask = srcRegisterMask;
|
*srcRegisterMask = ~static_cast<uint64_t>(0);
|
||||||
|
|
||||||
if ((dstTypeMask & (1 << MemoryOperand))
|
*tmpTypeMask = 0;
|
||||||
and (srcTypeMask & ((1 << MemoryOperand) | 1 << AddressOperand)))
|
*tmpRegisterMask = 0;
|
||||||
{
|
|
||||||
|
if (dstTypeMask & (1 << MemoryOperand)) {
|
||||||
// can't move directly from memory to memory
|
// can't move directly from memory to memory
|
||||||
*tmpTypeMask = (1 << RegisterOperand);
|
*srcTypeMask = (1 << RegisterOperand) | (1 << ConstantOperand);
|
||||||
|
*tmpTypeMask = 1 << RegisterOperand;
|
||||||
*tmpRegisterMask = GeneralRegisterMask
|
*tmpRegisterMask = GeneralRegisterMask
|
||||||
| (static_cast<uint64_t>(GeneralRegisterMask) << 32);
|
| (static_cast<uint64_t>(GeneralRegisterMask) << 32);
|
||||||
} else if (dstTypeMask & (1 << RegisterOperand)) {
|
} else if (dstTypeMask & (1 << RegisterOperand)) {
|
||||||
if (srcTypeMask & (1 << RegisterOperand)) {
|
if (size > BytesPerWord) {
|
||||||
if (size != BytesPerWord
|
|
||||||
and (((dstRegisterMask & FloatRegisterMask) == 0)
|
|
||||||
xor ((srcRegisterMask & FloatRegisterMask) == 0)))
|
|
||||||
{
|
|
||||||
// can't move directly from FPR to GPR or vice-versa for
|
// can't move directly from FPR to GPR or vice-versa for
|
||||||
// values larger than the GPR size
|
// values larger than the GPR size
|
||||||
*tmpTypeMask = (1 << MemoryOperand);
|
if (dstRegisterMask & FloatRegisterMask) {
|
||||||
*tmpRegisterMask = 0;
|
*srcRegisterMask = FloatRegisterMask
|
||||||
|
| (static_cast<uint64_t>(FloatRegisterMask) << 32);
|
||||||
|
*tmpTypeMask = 1 << MemoryOperand;
|
||||||
|
} else if (dstRegisterMask & GeneralRegisterMask) {
|
||||||
|
*srcRegisterMask = GeneralRegisterMask
|
||||||
|
| (static_cast<uint64_t>(GeneralRegisterMask) << 32);
|
||||||
|
*tmpTypeMask = 1 << MemoryOperand;
|
||||||
}
|
}
|
||||||
} else if ((dstRegisterMask & FloatRegisterMask)
|
}
|
||||||
and (srcTypeMask & (1 << ConstantOperand)))
|
if (dstRegisterMask & FloatRegisterMask) {
|
||||||
{
|
|
||||||
// can't move directly from constant to FPR
|
// can't move directly from constant to FPR
|
||||||
*tmpTypeMask = (1 << MemoryOperand);
|
*srcTypeMask &= ~(1 << ConstantOperand);
|
||||||
*tmpRegisterMask = 0;
|
if (size > BytesPerWord) {
|
||||||
|
*tmpTypeMask = 1 << MemoryOperand;
|
||||||
|
} else {
|
||||||
|
*tmpTypeMask = (1 << RegisterOperand) | (1 << MemoryOperand);
|
||||||
|
*tmpRegisterMask = GeneralRegisterMask
|
||||||
|
| (static_cast<uint64_t>(GeneralRegisterMask) << 32);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3211,7 +3256,7 @@ class MyArchitecture: public Assembler::Architecture {
|
|||||||
class MyAssembler: public Assembler {
|
class MyAssembler: public Assembler {
|
||||||
public:
|
public:
|
||||||
MyAssembler(System* s, Allocator* a, Zone* zone, MyArchitecture* arch):
|
MyAssembler(System* s, Allocator* a, Zone* zone, MyArchitecture* arch):
|
||||||
c(s, a, zone), arch_(arch)
|
c(s, a, zone, &(arch->c)), arch_(arch)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
virtual void setClient(Client* client) {
|
virtual void setClient(Client* client) {
|
||||||
|
44
src/x86.h
44
src/x86.h
@ -159,15 +159,17 @@ memoryBarrier()
|
|||||||
{
|
{
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
MemoryBarrier();
|
MemoryBarrier();
|
||||||
#else
|
#elif defined ARCH_x86_32
|
||||||
__asm__ __volatile__("": : :"memory");
|
__asm__ __volatile__("lock; addl $0,0(%%esp)": : :"memory");
|
||||||
#endif
|
#elif defined ARCH_x86_64
|
||||||
|
__asm__ __volatile__("mfence": : :"memory");
|
||||||
|
#endif // ARCH_x86_64
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
storeStoreMemoryBarrier()
|
storeStoreMemoryBarrier()
|
||||||
{
|
{
|
||||||
memoryBarrier();
|
__asm__ __volatile__("": : :"memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
@ -179,28 +181,24 @@ storeLoadMemoryBarrier()
|
|||||||
inline void
|
inline void
|
||||||
loadMemoryBarrier()
|
loadMemoryBarrier()
|
||||||
{
|
{
|
||||||
memoryBarrier();
|
__asm__ __volatile__("": : :"memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
syncInstructionCache(const void*, unsigned)
|
syncInstructionCache(const void*, unsigned)
|
||||||
{
|
{
|
||||||
// ignore
|
__asm__ __volatile__("": : :"memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_ATOMIC_OPERATIONS
|
#ifdef USE_ATOMIC_OPERATIONS
|
||||||
inline bool
|
inline bool
|
||||||
atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
|
atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_)
|
||||||
{
|
{
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# ifdef ARCH_x86_32
|
|
||||||
InterlockedCompareExchange(p, new_, old);
|
InterlockedCompareExchange(p, new_, old);
|
||||||
# elif defined ARCH_x86_64
|
|
||||||
InterlockedCompareExchange64(p, new_, old);
|
|
||||||
# endif // ARCH_x86_64
|
|
||||||
#elif (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1)
|
#elif (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1)
|
||||||
return __sync_bool_compare_and_swap(p, old, new_);
|
return __sync_bool_compare_and_swap(p, old, new_);
|
||||||
#elif defined ARCH_x86_32
|
#else
|
||||||
uint8_t result;
|
uint8_t result;
|
||||||
|
|
||||||
__asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
|
__asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
|
||||||
@ -209,7 +207,17 @@ atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
|
|||||||
: "memory");
|
: "memory");
|
||||||
|
|
||||||
return result != 0;
|
return result != 0;
|
||||||
#elif defined ARCH_x86_64
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
atomicCompareAndSwap64(uint64_t* p, uint64_t old, uint64_t new_)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
InterlockedCompareExchange64(p, new_, old);
|
||||||
|
#elif (__GNUC__ >= 4) && (__GNUC_MINOR__ >= 1)
|
||||||
|
return __sync_bool_compare_and_swap(p, old, new_);
|
||||||
|
#else
|
||||||
uint8_t result;
|
uint8_t result;
|
||||||
|
|
||||||
__asm__ __volatile__("lock; cmpxchgq %2, %0; setz %1"
|
__asm__ __volatile__("lock; cmpxchgq %2, %0; setz %1"
|
||||||
@ -218,6 +226,16 @@ atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
|
|||||||
: "memory");
|
: "memory");
|
||||||
|
|
||||||
return result != 0;
|
return result != 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
|
||||||
|
{
|
||||||
|
#ifdef ARCH_x86_32
|
||||||
|
return atomicCompareAndSwap32(reinterpret_cast<uint32_t*>(p), old, new_);
|
||||||
|
#elif defined ARCH_x86_64
|
||||||
|
return atomicCompareAndSwap64(reinterpret_cast<uint64_t*>(p), old, new_);
|
||||||
#endif // ARCH_x86_64
|
#endif // ARCH_x86_64
|
||||||
}
|
}
|
||||||
#endif // USE_ATOMIC_OPERATIONS
|
#endif // USE_ATOMIC_OPERATIONS
|
||||||
|
@ -19,6 +19,8 @@ public class AllFloats {
|
|||||||
private static float complex(float a, float b) {return (a - b) / (a * b) + (float)Math.sqrt(a);}
|
private static float complex(float a, float b) {return (a - b) / (a * b) + (float)Math.sqrt(a);}
|
||||||
private static double complex(double a, double b) {return (a - b) / (a * b) + Math.sqrt(a);}
|
private static double complex(double a, double b) {return (a - b) / (a * b) + Math.sqrt(a);}
|
||||||
private static double complex(float a, double b) {return (a - b) / (a * b) + Math.sqrt(a);}
|
private static double complex(float a, double b) {return (a - b) / (a * b) + Math.sqrt(a);}
|
||||||
|
private static double sqrt(double a) {return Math.sqrt(a);}
|
||||||
|
private static float complexNoIntrinsic(float a, float b) {return (a - b) / (a * b) + (float)sqrt(a);}
|
||||||
private static int f2i(float a) {return (int)a;}
|
private static int f2i(float a) {return (int)a;}
|
||||||
private static long f2l(float a) {return (long)a;}
|
private static long f2l(float a) {return (long)a;}
|
||||||
private static float i2f(int a) {return (float)a;}
|
private static float i2f(int a) {return (float)a;}
|
||||||
@ -59,6 +61,7 @@ public class AllFloats {
|
|||||||
expect(complex(4f, 3f) == (4f-3f)/(4f*3f) + 2f);
|
expect(complex(4f, 3f) == (4f-3f)/(4f*3f) + 2f);
|
||||||
expect(complex(4d, 3d) == (4d-3d)/(4d*3d) + 2d);
|
expect(complex(4d, 3d) == (4d-3d)/(4d*3d) + 2d);
|
||||||
expect(complex(4f, 3d) == (4f-3d)/(4f*3d) + 2f);
|
expect(complex(4f, 3d) == (4f-3d)/(4f*3d) + 2f);
|
||||||
|
expect(complexNoIntrinsic(4f, 3f) == (4f-3f)/(4f*3f) + 2f);
|
||||||
|
|
||||||
expect(f2i(4f) == 4);
|
expect(f2i(4f) == 4);
|
||||||
expect(f2l(4f) == 4);
|
expect(f2l(4f) == 4);
|
||||||
|
@ -19,6 +19,20 @@ public class Floats {
|
|||||||
return a - b;
|
return a - b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private double field = 100d;
|
||||||
|
|
||||||
|
private static int doubleToInt(Floats f) {
|
||||||
|
return (int) f.field;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void multiplyAndStore(double a, double b, Floats f) {
|
||||||
|
f.field = a * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double loadAndMultiply(double a, Floats f) {
|
||||||
|
return f.field * a;
|
||||||
|
}
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
expect(multiply(0.5d, 0.5d) == 0.25d);
|
expect(multiply(0.5d, 0.5d) == 0.25d);
|
||||||
expect(multiply(0.5f, 0.5f) == 0.25f);
|
expect(multiply(0.5f, 0.5f) == 0.25f);
|
||||||
@ -50,10 +64,35 @@ public class Floats {
|
|||||||
expect(((int) d) == 1);
|
expect(((int) d) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ double d = 12345d;
|
||||||
|
expect(((int) d) == 12345);
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(doubleToInt(new Floats()) == 100);
|
||||||
|
|
||||||
|
{ Floats f = new Floats();
|
||||||
|
f.field = 32.0d;
|
||||||
|
expect(loadAndMultiply(2.0d, f) == 64.0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Floats f = new Floats();
|
||||||
|
f.field = 32.0d;
|
||||||
|
expect(multiply(2.0d, f.field) == 64.0d);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ Floats f = new Floats();
|
||||||
|
multiplyAndStore(32.0d, 0.5d, f);
|
||||||
|
expect(f.field == 16.0d);
|
||||||
|
}
|
||||||
|
|
||||||
{ float f = 1f;
|
{ float f = 1f;
|
||||||
expect(((int) f) == 1);
|
expect(((int) f) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ float f = 1f;
|
||||||
|
expect(((long) f) == 1);
|
||||||
|
}
|
||||||
|
|
||||||
expect(Math.round(0.4f) == 0);
|
expect(Math.round(0.4f) == 0);
|
||||||
expect(Math.round(0.5f) == 1);
|
expect(Math.round(0.5f) == 1);
|
||||||
expect(Math.round(1.0f) == 1);
|
expect(Math.round(1.0f) == 1);
|
||||||
@ -73,5 +112,20 @@ public class Floats {
|
|||||||
double d = (double) z;
|
double d = (double) z;
|
||||||
expect(d == 6553311036568663.0);
|
expect(d == 6553311036568663.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{ long z = 12345L;
|
||||||
|
float f = (float) z;
|
||||||
|
expect(f == 12345.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ int z = 12345;
|
||||||
|
float f = (float) z;
|
||||||
|
expect(f == 12345.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ int z = 12345;
|
||||||
|
double d = (double) z;
|
||||||
|
expect(d == 12345.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user