[exdoc] Handle punctuation better in code formatting.
[mono.git] / mono / mini / mini-arm.c
index 70113d9fde71a2816dff322d195a4a549ced0b75..30107af99ccf076dc30832114815a0aff6256ce7 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * mini-arm.c: ARM backend for the Mono code generator
+/**
+ * \file
+ * ARM backend for the Mono code generator
  *
  * Authors:
  *   Paolo Molaro (lupus@ximian.com)
@@ -322,10 +323,54 @@ mono_arm_patchable_bl (guint8 *code, int cond)
        return code;
 }
 
+#if defined(__ARM_EABI__) && defined(__linux__) && !defined(PLATFORM_ANDROID) && !defined(__native_client__)
+#define HAVE_AEABI_READ_TP 1
+#endif
+
+#ifdef HAVE_AEABI_READ_TP
+gpointer __aeabi_read_tp (void);
+#endif
+
 gboolean
 mono_arch_have_fast_tls (void)
 {
+#ifdef HAVE_AEABI_READ_TP
+       static gboolean have_fast_tls = FALSE;
+        static gboolean inited = FALSE;
+       gpointer tp1, tp2;
+
+       if (mini_get_debug_options ()->use_fallback_tls)
+               return FALSE;
+
+       if (inited)
+               return have_fast_tls;
+
+       tp1 = __aeabi_read_tp ();
+       asm volatile("mrc p15, 0, %0, c13, c0, 3" : "=r" (tp2));
+
+       have_fast_tls = tp1 && tp1 == tp2;
+       inited = TRUE;
+       return have_fast_tls;
+#else
        return FALSE;
+#endif
+}
+
+static guint8*
+emit_tls_get (guint8 *code, int dreg, int tls_offset)
+{
+       ARM_MRC (code, 15, 0, dreg, 13, 0, 3);
+       ARM_LDR_IMM (code, dreg, dreg, tls_offset);
+       return code;
+}
+
+static guint8*
+emit_tls_set (guint8 *code, int sreg, int tls_offset)
+{
+       int tp_reg = (sreg != ARMREG_R0) ? ARMREG_R0 : ARMREG_R1;
+       ARM_MRC (code, 15, 0, tp_reg, 13, 0, 3);
+       ARM_STR_IMM (code, sreg, tp_reg, tls_offset);
+       return code;
 }
 
 /*
@@ -339,9 +384,13 @@ emit_save_lmf (MonoCompile *cfg, guint8 *code, gint32 lmf_offset)
 {
        int i;
 
-       mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD, 
-                                                (gpointer)"mono_get_lmf_addr");
-       code = emit_call_seq (cfg, code);
+       if (mono_arch_have_fast_tls () && mono_tls_get_tls_offset (TLS_KEY_LMF_ADDR) != -1) {
+               code = emit_tls_get (code, ARMREG_R0, mono_tls_get_tls_offset (TLS_KEY_LMF_ADDR));
+       } else {
+               mono_add_patch_info (cfg, code - cfg->native_code, MONO_PATCH_INFO_INTERNAL_METHOD,
+                                                        (gpointer)"mono_tls_get_lmf_addr");
+               code = emit_call_seq (cfg, code);
+       }
        /* we build the MonoLMF structure on the stack - see mini-arm.h */
        /* lmf_offset is the offset from the previous stack pointer,
         * alloc_size is the total stack space allocated, so the offset
@@ -733,7 +782,7 @@ mono_arch_init (void)
        mono_aot_register_jit_icall ("mono_arm_start_gsharedvt_call", mono_arm_start_gsharedvt_call);
 #endif
        mono_aot_register_jit_icall ("mono_arm_unaligned_stack", mono_arm_unaligned_stack);
-
+       mono_aot_register_jit_icall ("mono_arm_handler_block_trampoline_helper", mono_arm_handler_block_trampoline_helper);
 #if defined(__ARM_EABI__)
        eabi_supported = TRUE;
 #endif
@@ -743,7 +792,7 @@ mono_arch_init (void)
 #else
        arm_fpu = MONO_ARM_FPU_VFP;
 
-#if defined(ARM_FPU_NONE) && !defined(__APPLE__)
+#if defined(ARM_FPU_NONE) && !defined(TARGET_IOS)
        /*
         * If we're compiling with a soft float fallback and it
         * turns out that no VFP unit is available, we need to
@@ -785,7 +834,7 @@ mono_arch_init (void)
        v7_supported = TRUE;
 #endif
 
-#if defined(__APPLE__)
+#if defined(TARGET_IOS)
        /* iOS is special-cased here because we don't yet
           have a way to properly detect CPU features on it. */
        thumb_supported = TRUE;
@@ -1467,6 +1516,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig)
                        nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer);
                        ainfo->storage = RegTypeStructByVal;
                        ainfo->struct_size = size;
+                       ainfo->align = align;
                        /* FIXME: align stack_size if needed */
                        if (eabi_supported) {
                                if (align >= 8 && (gr & 1))
@@ -1598,8 +1648,7 @@ debug_omit_fp (void)
 
 /**
  * mono_arch_compute_omit_fp:
- *
- *   Determine whenever the frame pointer can be eliminated.
+ * Determine whether the frame pointer can be eliminated.
  */
 static void
 mono_arch_compute_omit_fp (MonoCompile *cfg)
@@ -2091,6 +2140,11 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
                linfo->ret.nslots = cinfo->ret.nregs;
                break;
 #endif
+       case RegTypeHFA:
+               linfo->ret.storage = LLVMArgFpStruct;
+               linfo->ret.nslots = cinfo->ret.nregs;
+               linfo->ret.esize = cinfo->ret.esize;
+               break;
        default:
                cfg->exception_message = g_strdup_printf ("unknown ret conv (%d)", cinfo->ret.storage);
                cfg->disable_llvm = TRUE;
@@ -2113,12 +2167,31 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig)
                        break;
                case RegTypeStructByVal:
                        lainfo->storage = LLVMArgAsIArgs;
-                       lainfo->nslots = ainfo->struct_size / sizeof (gpointer);
+                       if (eabi_supported && ainfo->align == 8) {
+                               /* LLVM models this by passing an int64 array */
+                               lainfo->nslots = ALIGN_TO (ainfo->struct_size, 8) / 8;
+                               lainfo->esize = 8;
+                       } else {
+                               lainfo->nslots = ainfo->struct_size / sizeof (gpointer);
+                               lainfo->esize = 4;
+                       }
+
+                       printf ("D: %d\n", ainfo->align);
                        break;
                case RegTypeStructByAddr:
                case RegTypeStructByAddrOnStack:
                        lainfo->storage = LLVMArgVtypeByRef;
                        break;
+               case RegTypeHFA: {
+                       int j;
+
+                       lainfo->storage = LLVMArgAsFpArgs;
+                       lainfo->nslots = ainfo->nregs;
+                       lainfo->esize = ainfo->esize;
+                       for (j = 0; j < ainfo->nregs; ++j)
+                               lainfo->pair_storage [j] = LLVMArgInFPReg;
+                       break;
+               }
                default:
                        cfg->exception_message = g_strdup_printf ("ainfo->storage (%d)", ainfo->storage);
                        cfg->disable_llvm = TRUE;
@@ -4149,6 +4222,12 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                ARM_MCR (code, 15, 0, ARMREG_R0, 7, 10, 5);
                        }
                        break;
+               case OP_TLS_GET:
+                       code = emit_tls_get (code, ins->dreg, ins->inst_offset);
+                       break;
+               case OP_TLS_SET:
+                       code = emit_tls_set (code, ins->sreg1, ins->inst_offset);
+                       break;
                case OP_ATOMIC_EXCHANGE_I4:
                case OP_ATOMIC_CAS_I4:
                case OP_ATOMIC_ADD_I4: {
@@ -7367,3 +7446,17 @@ emit_aotconst (MonoCompile *cfg, guint8 *code, int dreg, int patch_type, gpointe
        ARM_LDR_REG_REG (code, dreg, ARMREG_PC, dreg);
        return code;
 }
+
+guint8*
+mono_arm_emit_aotconst (gpointer ji_list, guint8 *code, guint8 *buf, int dreg, int patch_type, gconstpointer data)
+{
+       MonoJumpInfo **ji = (MonoJumpInfo**)ji_list;
+
+       *ji = mono_patch_info_list_prepend (*ji, code - buf, patch_type, data);
+       ARM_LDR_IMM (code, dreg, ARMREG_PC, 0);
+       ARM_B (code, 0);
+       *(gpointer*)code = NULL;
+       code += 4;
+       ARM_LDR_REG_REG (code, dreg, ARMREG_PC, dreg);
+       return code;
+}