add process=interpret support for Linux/ARM64

This makes all the tests pass for the platform=linux arch=arm64
process=interpret build.  Next step: process=compile support.
This commit is contained in:
Joel Dice 2014-11-25 18:36:34 -07:00
parent 66f1b7cf8f
commit d52d0f6d96
11 changed files with 239 additions and 52 deletions

View File

@ -118,6 +118,7 @@ class PlatformInfo {
x86 = AVIAN_ARCH_X86, x86 = AVIAN_ARCH_X86,
x86_64 = AVIAN_ARCH_X86_64, x86_64 = AVIAN_ARCH_X86_64,
Arm = AVIAN_ARCH_ARM, Arm = AVIAN_ARCH_ARM,
Arm64 = AVIAN_ARCH_ARM64,
UnknownArch = AVIAN_ARCH_UNKNOWN UnknownArch = AVIAN_ARCH_UNKNOWN
}; };

View File

@ -7,7 +7,8 @@ build-arch := $(shell uname -m \
| sed 's/^i.86$$/i386/' \ | sed 's/^i.86$$/i386/' \
| sed 's/^x86pc$$/i386/' \ | sed 's/^x86pc$$/i386/' \
| sed 's/amd64/x86_64/' \ | sed 's/amd64/x86_64/' \
| sed 's/^arm.*$$/arm/') | sed 's/^arm.*$$/arm/' \
| sed 's/aarch64/arm64/')
build-platform := \ build-platform := \
$(shell uname -s | tr [:upper:] [:lower:] \ $(shell uname -s | tr [:upper:] [:lower:] \
@ -62,8 +63,8 @@ ifeq ($(filter compile interpret,$(process)),)
x := $(error "'$(process)' is not a valid process (choose one of: compile interpret)") x := $(error "'$(process)' is not a valid process (choose one of: compile interpret)")
endif endif
ifeq ($(filter x86_64 i386 arm,$(arch)),) ifeq ($(filter x86_64 i386 arm arm64,$(arch)),)
x := $(error "'$(arch)' is not a supported architecture (choose one of: x86_64 i386 arm)") x := $(error "'$(arch)' is not a supported architecture (choose one of: x86_64 i386 arm arm64)")
endif endif
ifeq ($(platform),darwin) ifeq ($(platform),darwin)
@ -79,8 +80,8 @@ ifeq ($(filter linux windows macosx ios freebsd,$(platform)),)
endif endif
ifeq ($(platform),macosx) ifeq ($(platform),macosx)
ifeq ($(arch),arm) ifneq ($(filter arm arm64,$(arch),)
x := $(error "please use 'arch=arm' 'platform=ios' to build for ios-arm") x := $(error "please use 'arch=arm' or 'arch=arm64' 'platform=ios' to build for ios-arm")
endif endif
endif endif
@ -520,15 +521,15 @@ codeimage-symbols = _binary_codeimage_bin_start:_binary_codeimage_bin_end
developer-dir := $(shell if test -d /Developer/Platforms/$(target).platform/Developer/SDKs; then echo /Developer; \ developer-dir := $(shell if test -d /Developer/Platforms/$(target).platform/Developer/SDKs; then echo /Developer; \
else echo /Applications/Xcode.app/Contents/Developer; fi) else echo /Applications/Xcode.app/Contents/Developer; fi)
ifeq ($(arch),i386) ifneq (,$(filter i386 arm,$(arch)))
pointer-size = 4 pointer-size = 4
endif endif
ifeq ($(arch),arm) ifneq (,$(filter arm arm64,$(arch)))
asm = arm asm = arm
pointer-size = 4
ifneq ($(platform),ios) ifneq ($(platform),ios)
ifneq ($(arch),arm64)
no-psabi = -Wno-psabi no-psabi = -Wno-psabi
cflags += -marm $(no-psabi) cflags += -marm $(no-psabi)
@ -536,9 +537,17 @@ ifeq ($(arch),arm)
# non-iOS platforms. Ideally, we'd detect this at runtime. # non-iOS platforms. Ideally, we'd detect this at runtime.
armv6=true armv6=true
endif endif
endif
ifneq ($(arch),$(build-arch)) ifneq ($(arch),$(build-arch))
ifneq ($(kernel),darwin) ifneq ($(kernel),darwin)
ifeq ($(arch),arm64)
cxx = aarch64-linux-gnu-g++
cc = aarch64-linux-gnu-gcc
ar = aarch64-linux-gnu-ar
ranlib = aarch64-linux-gnu-ranlib
strip = aarch64-linux-gnu-strip
else
cxx = arm-linux-gnueabi-g++ cxx = arm-linux-gnueabi-g++
cc = arm-linux-gnueabi-gcc cc = arm-linux-gnueabi-gcc
ar = arm-linux-gnueabi-ar ar = arm-linux-gnueabi-ar
@ -546,6 +555,7 @@ ifeq ($(arch),arm)
strip = arm-linux-gnueabi-strip strip = arm-linux-gnueabi-strip
endif endif
endif endif
endif
endif endif
ifeq ($(armv6),true) ifeq ($(armv6),true)
@ -721,7 +731,11 @@ ifeq ($(kernel),darwin)
else else
target = iPhoneOS target = iPhoneOS
sdk = iphoneos$(ios-version) sdk = iphoneos$(ios-version)
ifeq ($(arch),arm)
arch-flag = -arch armv7 arch-flag = -arch armv7
else
arch-flag = -arch arm64
endif
release = Release-iphoneos release = Release-iphoneos
endif endif
@ -1234,7 +1248,7 @@ ifeq ($(process),compile)
vm-sources += $(native-assembler-sources) vm-sources += $(native-assembler-sources)
endif endif
ifeq ($(codegen-targets),all) ifeq ($(codegen-targets),all)
ifeq ($(arch),arm) ifneq (,$(filter arm arm64,$(arch)))
# The x86 jit has a dependency on the x86 assembly code, # The x86 jit has a dependency on the x86 assembly code,
# and thus can't be successfully built on non-x86 platforms. # and thus can't be successfully built on non-x86 platforms.
vm-sources += $(native-assembler-sources) vm-sources += $(native-assembler-sources)
@ -1511,6 +1525,10 @@ ifeq ($(target-arch),arm)
cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM
endif endif
ifeq ($(target-arch),arm64)
cflags += -DAVIAN_TARGET_ARCH=AVIAN_ARCH_ARM64
endif
ifeq ($(target-format),elf) ifeq ($(target-format),elf)
cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_ELF cflags += -DAVIAN_TARGET_FORMAT=AVIAN_FORMAT_ELF
endif endif

130
src/arm.S
View File

@ -21,6 +21,134 @@
# define GLOBAL(x) x # define GLOBAL(x) x
#endif #endif
#ifdef __aarch64__
.globl GLOBAL(vmNativeCall)
.align 2
GLOBAL(vmNativeCall):
// arguments:
// x0 -> x19 : function
// w1 -> w20 : stackTotal
// x2 : memoryTable
// w3 : memoryCount
// x4 -> x21 : gprTable
// x5 -> x22 : vfpTable
// w6 -> w23 : returnType
// allocate frame
stp x29, x30, [sp,#-64]!
// save callee-saved register values so we can clobber them
stp x19, x20, [sp,#16]
stp x21, x22, [sp,#32]
str x23, [sp,#48]
// move arguments into callee-saved registers
mov x19, x0
mov w20, w1
mov x21, x4
mov x22, x5
mov w23, w6
// setup stack arguments if necessary
sub sp, sp, w20 // allocate stack
mov x9, sp
LOCAL(loop):
cmp w3, wzr
b.eq LOCAL(populateGPRs)
ldr x0, [x2], #8
str x0, [x9], #8
sub w3, w3, #8
b LOCAL(loop)
LOCAL(populateGPRs):
cmp x21, xzr
b.eq LOCAL(populateVFPs)
ldp x0, x1, [x21]
ldp x2, x3, [x21,#16]
ldp x4, x5, [x21,#32]
ldp x6, x7, [x21,#48]
LOCAL(populateVFPs):
cmp x22, xzr
b.eq LOCAL(doCall)
ldp d0, d1, [x22]
ldp d2, d3, [x22,#16]
ldp d4, d5, [x22,#32]
ldp d6, d7, [x22,#48]
LOCAL(doCall):
blr x19 // call function
add sp, sp, w20 // deallocate stack
cmp w23,#FLOAT_TYPE
bne LOCAL(double)
fmov w0,s0
b LOCAL(exit)
LOCAL(double):
cmp w23,#DOUBLE_TYPE
bne LOCAL(exit)
fmov x0,d0
LOCAL(exit):
ldp x19, x20, [sp,#16]
ldp x21, x22, [sp,#32]
ldr x23, [sp,#48]
ldp x29, x30, [sp],#64
ret
.globl GLOBAL(vmJump)
.align 2
GLOBAL(vmJump):
mov x30, x0
mov x0, x4
mov x1, x5
mov sp, x2
mov x19, x3
br x30
#define CHECKPOINT_THREAD 8
#define CHECKPOINT_STACK 48
.globl GLOBAL(vmRun)
.align 2
GLOBAL(vmRun):
// x0: function
// x1: arguments
// x2: checkpoint
// allocate frame
stp x29, x30, [sp,#-96]!
// save callee-saved register values
stp x19, x20, [sp,#16]
stp x21, x22, [sp,#32]
stp x23, x24, [sp,#48]
stp x25, x26, [sp,#64]
stp x27, x28, [sp,#80]
mov x19, sp
str x19, [x2, #CHECKPOINT_STACK]
mov x19, x0
ldr x0, [x2, #CHECKPOINT_THREAD]
blr x19
.globl GLOBAL(vmRun_returnAddress)
.align 2
GLOBAL(vmRun_returnAddress):
ldp x19, x20, [sp,#16]
ldp x21, x22, [sp,#32]
ldp x23, x24, [sp,#48]
ldp x25, x26, [sp,#64]
ldp x27, x28, [sp,#80]
ldp x29, x30, [sp],#96
br x30
#elif defined __arm__
.globl GLOBAL(vmNativeCall) .globl GLOBAL(vmNativeCall)
.align 2 .align 2
GLOBAL(vmNativeCall): GLOBAL(vmNativeCall):
@ -130,3 +258,5 @@ GLOBAL(vmRun_returnAddress):
add sp, sp, #12 add sp, sp, #12
ldmfd sp!, {r4-r11, lr} ldmfd sp!, {r4-r11, lr}
bx lr bx lr
#endif // __arm__

View File

@ -43,7 +43,7 @@ inline void compileTimeMemoryBarrier()
#if (defined ARCH_x86_32) || (defined ARCH_x86_64) #if (defined ARCH_x86_32) || (defined ARCH_x86_64)
#include "x86.h" #include "x86.h"
#elif defined ARCH_arm #elif (defined ARCH_arm) || (defined ARCH_arm64)
#include "arm.h" #include "arm.h"
#else #else
#error unsupported architecture #error unsupported architecture

View File

@ -53,10 +53,17 @@
#define THREAD_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_IP]) #define THREAD_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_IP])
#define LINK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_LR]) #define LINK_REGISTER(context) (context->uc_mcontext.cpu.gpr[ARM_REG_LR])
#else #else
#ifdef ARCH_arm
#define IP_REGISTER(context) (context->uc_mcontext.arm_pc) #define IP_REGISTER(context) (context->uc_mcontext.arm_pc)
#define STACK_REGISTER(context) (context->uc_mcontext.arm_sp) #define STACK_REGISTER(context) (context->uc_mcontext.arm_sp)
#define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip) #define THREAD_REGISTER(context) (context->uc_mcontext.arm_ip)
#define LINK_REGISTER(context) (context->uc_mcontext.arm_lr) #define LINK_REGISTER(context) (context->uc_mcontext.arm_lr)
#else
#define IP_REGISTER(context) (context->uc_mcontext.pc)
#define STACK_REGISTER(context) (context->uc_mcontext.sp)
#define THREAD_REGISTER(context) (context->uc_mcontext.regs[19])
#define LINK_REGISTER(context) (context->uc_mcontext.regs[30])
#endif
#endif #endif
#define VA_LIST(x) (&(x)) #define VA_LIST(x) (&(x))
@ -76,7 +83,7 @@ inline void trap()
#ifdef _MSC_VER #ifdef _MSC_VER
__debugbreak(); __debugbreak();
#else #else
asm("bkpt"); asm("brk 0");
#endif #endif
} }
@ -162,6 +169,8 @@ inline bool atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_)
old, new_, reinterpret_cast<int32_t*>(p)); old, new_, reinterpret_cast<int32_t*>(p));
#elif(defined __QNX__) #elif(defined __QNX__)
return old == _smp_cmpxchg(p, old, new_); return old == _smp_cmpxchg(p, old, new_);
#elif (defined ARCH_arm64)
return __sync_bool_compare_and_swap(p, old, new_);
#else #else
int r = __kernel_cmpxchg( int r = __kernel_cmpxchg(
static_cast<int>(old), static_cast<int>(new_), reinterpret_cast<int*>(p)); static_cast<int>(old), static_cast<int>(new_), reinterpret_cast<int*>(p));
@ -169,10 +178,22 @@ inline bool atomicCompareAndSwap32(uint32_t* p, uint32_t old, uint32_t new_)
#endif #endif
} }
#ifdef ARCH_arm64
inline bool atomicCompareAndSwap64(uint64_t* p, uint64_t old, uint64_t new_)
{
return __sync_bool_compare_and_swap(p, old, new_);
}
inline bool atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
{
return atomicCompareAndSwap64(reinterpret_cast<uint64_t*>(p), old, new_);
}
#else
inline bool atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_) inline bool atomicCompareAndSwap(uintptr_t* p, uintptr_t old, uintptr_t new_)
{ {
return atomicCompareAndSwap32(reinterpret_cast<uint32_t*>(p), old, new_); return atomicCompareAndSwap32(reinterpret_cast<uint32_t*>(p), old, new_);
} }
#endif
inline uint64_t dynamicCall(void* function, inline uint64_t dynamicCall(void* function,
uintptr_t* arguments, uintptr_t* arguments,
@ -181,17 +202,17 @@ inline uint64_t dynamicCall(void* function,
unsigned argumentsSize UNUSED, unsigned argumentsSize UNUSED,
unsigned returnType) unsigned returnType)
{ {
#ifdef __APPLE__ #if (defined __APPLE__) || (defined ARCH_arm64)
const unsigned Alignment = 1; const unsigned Alignment = 1;
#else #else
const unsigned Alignment = 2; const unsigned Alignment = 2;
#endif #endif
const unsigned GprCount = 4; const unsigned GprCount = BytesPerWord;
uintptr_t gprTable[GprCount]; uintptr_t gprTable[GprCount];
unsigned gprIndex = 0; unsigned gprIndex = 0;
const unsigned VfpCount = 16; const unsigned VfpCount = BytesPerWord == 8 ? 8 : 16;
uintptr_t vfpTable[VfpCount]; uintptr_t vfpTable[VfpCount];
unsigned vfpIndex = 0; unsigned vfpIndex = 0;
unsigned vfpBackfillIndex UNUSED = 0; unsigned vfpBackfillIndex UNUSED = 0;
@ -206,7 +227,7 @@ inline uint64_t dynamicCall(void* function,
for (unsigned ati = 0; ati < argumentCount; ++ati) { for (unsigned ati = 0; ati < argumentCount; ++ati) {
switch (argumentTypes[ati]) { switch (argumentTypes[ati]) {
case DOUBLE_TYPE: case DOUBLE_TYPE:
#if defined(__ARM_PCS_VFP) #if (defined __ARM_PCS_VFP) || (defined ARCH_arm64)
{ {
if (vfpIndex + Alignment <= VfpCount) { if (vfpIndex + Alignment <= VfpCount) {
if (vfpIndex % Alignment) { if (vfpIndex % Alignment) {

View File

@ -116,6 +116,8 @@ typedef intptr_t intptr_alias_t;
#define ARCH_x86_64 #define ARCH_x86_64
#elif defined __arm__ #elif defined __arm__
#define ARCH_arm #define ARCH_arm
#elif defined __aarch64__
#define ARCH_arm64
#else #else
#error "unsupported architecture" #error "unsupported architecture"
#endif #endif

View File

@ -28,5 +28,6 @@
#define AVIAN_ARCH_X86 (1 << 8) #define AVIAN_ARCH_X86 (1 << 8)
#define AVIAN_ARCH_X86_64 (2 << 8) #define AVIAN_ARCH_X86_64 (2 << 8)
#define AVIAN_ARCH_ARM (3 << 8) #define AVIAN_ARCH_ARM (3 << 8)
#define AVIAN_ARCH_ARM64 (4 << 8)
#endif #endif

View File

@ -52,10 +52,17 @@ inline int fpr32(lir::Register* reg)
return fpr64(reg) << 1; return fpr64(reg) << 1;
} }
#ifdef ARCH_arm64
const int ThreadRegister = 19;
const int StackRegister = 31;
const int LinkRegister = 30;
const int ProgramCounter = 0xFF; // i.e. unaddressable
#else
const int ThreadRegister = 8; const int ThreadRegister = 8;
const int StackRegister = 13; const int StackRegister = 13;
const int LinkRegister = 14; const int LinkRegister = 14;
const int ProgramCounter = 15; const int ProgramCounter = 15;
#endif
} // namespace arm } // namespace arm
} // namespace codegen } // namespace codegen

View File

@ -30,7 +30,8 @@ Architecture* makeArchitectureNative(vm::System* system,
#elif(AVIAN_TARGET_ARCH == AVIAN_ARCH_X86) \ #elif(AVIAN_TARGET_ARCH == AVIAN_ARCH_X86) \
|| (AVIAN_TARGET_ARCH == AVIAN_ARCH_X86_64) || (AVIAN_TARGET_ARCH == AVIAN_ARCH_X86_64)
return makeArchitectureX86(system, useNativeFeatures); return makeArchitectureX86(system, useNativeFeatures);
#elif AVIAN_TARGET_ARCH == AVIAN_ARCH_ARM #elif (AVIAN_TARGET_ARCH == AVIAN_ARCH_ARM) \
|| (AVIAN_TARGET_ARCH == AVIAN_ARCH_ARM64)
return makeArchitectureArm(system, useNativeFeatures); return makeArchitectureArm(system, useNativeFeatures);
#else #else
#error "Unsupported codegen target" #error "Unsupported codegen target"

View File

@ -49,6 +49,7 @@
#define EM_386 3 #define EM_386 3
#define EM_X86_64 62 #define EM_X86_64 62
#define EM_ARM 40 #define EM_ARM 40
#define EM_AARCH64 183
#define SHT_PROGBITS 1 #define SHT_PROGBITS 1
#define SHT_SYMTAB 2 #define SHT_SYMTAB 2
@ -129,6 +130,8 @@ unsigned getElfPlatform(PlatformInfo::Architecture arch)
return EM_386; return EM_386;
case PlatformInfo::Arm: case PlatformInfo::Arm:
return EM_ARM; return EM_ARM;
case PlatformInfo::Arm64:
return EM_AARCH64;
default: default:
return ~0; return ~0;
} }
@ -398,6 +401,7 @@ class ElfPlatform : public Platform {
ElfPlatform<uint32_t> elfX86Platform(PlatformInfo::x86); ElfPlatform<uint32_t> elfX86Platform(PlatformInfo::x86);
ElfPlatform<uint32_t> elfArmPlatform(PlatformInfo::Arm); ElfPlatform<uint32_t> elfArmPlatform(PlatformInfo::Arm);
ElfPlatform<uint64_t> elfArm64Platform(PlatformInfo::Arm64);
ElfPlatform<uint64_t> elfX86_64Platform(PlatformInfo::x86_64); ElfPlatform<uint64_t> elfX86_64Platform(PlatformInfo::x86_64);
} // namespace } // namespace

View File

@ -115,6 +115,8 @@ PlatformInfo::Architecture PlatformInfo::archFromString(const char* arch)
return Architecture::x86_64; return Architecture::x86_64;
} else if (strcmp(arch, "arm") == 0) { } else if (strcmp(arch, "arm") == 0) {
return Architecture::Arm; return Architecture::Arm;
} else if (strcmp(arch, "arm64") == 0) {
return Architecture::Arm64;
} else { } else {
return Architecture::UnknownArch; return Architecture::UnknownArch;
} }