(root)/
gcc-13.2.0/
gcc/
testsuite/
jit.dg/
test-asm.c
       1  /* { dg-do compile { target x86_64-*-* } } */
       2  
       3  #include <stdlib.h>
       4  #include <stdio.h>
       5  #include <string.h>
       6  #include <stdint.h>
       7  
       8  #include "libgccjit.h"
       9  
      10  #include "harness.h"
      11  
      12  /**********************************************************************
      13   Support fns for creating code.
      14   **********************************************************************/
      15  
      16  /* Make a "void FUNC_NAME (void)" function with a single block, returning
      17     that block.  */
      18  
      19  static gcc_jit_block *
      20  make_single_block_func (gcc_jit_context *ctxt, const char *func_name)
      21  {
      22    gcc_jit_type *void_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
      23    gcc_jit_function *func
      24      = gcc_jit_context_new_function (ctxt, NULL,
      25  				    GCC_JIT_FUNCTION_EXPORTED,
      26  				    void_type,
      27  				    func_name,
      28  				    0, NULL, 0);
      29    return gcc_jit_function_new_block (func, "initial");
      30  }
      31  
      32  static const char *
      33  get_desc (gcc_jit_extended_asm *ext_asm)
      34  {
      35    return gcc_jit_object_get_debug_string
      36      (gcc_jit_extended_asm_as_object (ext_asm));
      37  }
      38  
      39  /**********************************************************************
      40   Support fns for verifying code.
      41   **********************************************************************/
      42  
      43  typedef void (*void_void_fn) (void);
      44  
      45  static void_void_fn
      46  get_test_fn (gcc_jit_result *result, const char *func_name)
      47  {
      48    return (void_void_fn)gcc_jit_result_get_code (result, func_name);
      49  }
      50  
      51  /**********************************************************************
      52   test_i386_basic_asm_1: simple example of asm
      53   **********************************************************************/
      54  
      55  /* Create the equivalent of:
      56  
      57       int src;
      58       int dst;
      59  
      60       void test_i386_basic_asm_1 (void)
      61       {
      62         // Quote from here in docs/topics/asm.rst: example 1: C
      63         asm ("mov %1, %0\n\t"
      64              "add $1, %0"
      65              : "=r" (dst)
      66              : "r" (src));
      67         // Quote up to here in docs/topics/asm.rst: example 1: C
      68       }
      69  
      70       i.e. copy src to dst and add 1 to dst.  */
      71  
      72  static void
      73  create_test_i386_basic_asm_1 (gcc_jit_context *ctxt)
      74  {
      75    gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
      76    gcc_jit_lvalue *dst
      77      = gcc_jit_context_new_global (ctxt, NULL,
      78  				  GCC_JIT_GLOBAL_EXPORTED,
      79  				  int_type, "dst");
      80    gcc_jit_lvalue *src
      81      = gcc_jit_context_new_global (ctxt, NULL,
      82  				  GCC_JIT_GLOBAL_EXPORTED,
      83  				  int_type, "src");
      84  
      85    gcc_jit_block *block
      86      = make_single_block_func (ctxt, "test_i386_basic_asm_1");
      87  
      88    /* Quote from here in docs/topics/asm.rst: example 1: jit.  */
      89    gcc_jit_extended_asm *ext_asm
      90      = gcc_jit_block_add_extended_asm (block, NULL,
      91  				      "mov %1, %0\n\t"
      92  				      "add $1, %0");
      93    gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst);
      94    gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
      95  					  gcc_jit_lvalue_as_rvalue (src));
      96    /* Quote up to here in docs/topics/asm.rst: example 1: jit.  */
      97  
      98    const char *desc = get_desc (ext_asm);
      99    CHECK_STRING_VALUE
     100      (desc,
     101       "asm (\"mov %1, %0\\n\\tadd $1, %0\" : \"=r\" (dst) : \"r\" (src) : )");
     102  
     103    gcc_jit_block_end_with_void_return (block, NULL);
     104  }
     105  
     106  static void
     107  verify_code_1 (gcc_jit_context *ctxt, gcc_jit_result *result)
     108  {
     109    void_void_fn test_i386_basic_asm_1
     110      = get_test_fn (result, "test_i386_basic_asm_1");
     111    CHECK_NON_NULL (test_i386_basic_asm_1);
     112  
     113    int *dst_ptr = (int *)gcc_jit_result_get_global (result, "dst");
     114    CHECK_NON_NULL (dst_ptr);
     115    int *src_ptr = (int *)gcc_jit_result_get_global (result, "src");
     116    CHECK_NON_NULL (src_ptr);
     117  
     118    *src_ptr = 42;
     119    *dst_ptr = 0;
     120    test_i386_basic_asm_1 ();
     121    CHECK_VALUE (*src_ptr, 42);
     122    CHECK_VALUE (*dst_ptr, 43);
     123  }
     124  
     125  /**********************************************************************
     126   test_i386_basic_asm_2: test of symbolic names and clobbers
     127   **********************************************************************/
     128  
     129  /* Create the equivalent of:
     130       uint32_t test_i386_basic_asm_2 (uint32_t Mask)
     131       {
     132         uint32_t Index;
     133         // Quote from here in docs/topics/asm.rst: example 2: C
     134         asm ("bsfl %[aMask], %[aIndex]"
     135              : [aIndex] "=r" (Index)
     136              : [aMask] "r" (Mask)
     137              : "cc");
     138         // Quote up to here in docs/topics/asm.rst: example 2: C
     139         return Index;
     140       }
     141     i.e. return the first bit set in "Mask"
     142  
     143     This exercises symbolic names and clobbers.  */
     144  
     145  static void
     146  create_test_i386_basic_asm_2 (gcc_jit_context *ctxt)
     147  {
     148    gcc_jit_type *uint32_type = gcc_jit_context_get_int_type (ctxt, 4, 0);
     149    gcc_jit_param *mask
     150      = gcc_jit_context_new_param (ctxt, NULL,
     151  				 uint32_type, "Mask");
     152    gcc_jit_function *func
     153      = gcc_jit_context_new_function (ctxt, NULL,
     154  				    GCC_JIT_FUNCTION_EXPORTED,
     155  				    uint32_type,
     156  				    "test_i386_basic_asm_2",
     157  				    1, &mask, 0);
     158    gcc_jit_lvalue *index
     159      = gcc_jit_function_new_local (func, NULL,
     160  				  uint32_type, "Index");
     161    gcc_jit_block *block = gcc_jit_function_new_block (func, "initial");
     162  
     163    /* Quote from here in docs/topics/asm.rst: example 2: jit.  */
     164    gcc_jit_extended_asm *ext_asm
     165      = gcc_jit_block_add_extended_asm (block, NULL,
     166  				      "bsfl %[aMask], %[aIndex]");
     167    gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index);
     168    gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r",
     169  					  gcc_jit_param_as_rvalue (mask));
     170    gcc_jit_extended_asm_add_clobber (ext_asm, "cc");
     171    /* Quote up to here in docs/topics/asm.rst: example 2: jit.  */
     172  
     173    const char *desc = get_desc (ext_asm);
     174    CHECK_STRING_VALUE
     175      (desc,
     176       "asm (\"bsfl %[aMask], %[aIndex]\""
     177       " : [aIndex] \"=r\" (Index) : [aMask] \"r\" (Mask) : \"cc\")");
     178  
     179    gcc_jit_block_end_with_return (block, NULL,
     180  				 gcc_jit_lvalue_as_rvalue (index));
     181  }
     182  
     183  static void
     184  verify_code_2 (gcc_jit_context *ctxt, gcc_jit_result *result)
     185  {
     186    typedef uint32_t (*fntype) (uint32_t);
     187    fntype test_i386_basic_asm_2
     188      = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_2");
     189    CHECK_NON_NULL (test_i386_basic_asm_2);
     190  
     191    CHECK_VALUE (test_i386_basic_asm_2 (1), 0);
     192    CHECK_VALUE (test_i386_basic_asm_2 (2), 1);
     193    CHECK_VALUE (test_i386_basic_asm_2 (4), 2);
     194    CHECK_VALUE (test_i386_basic_asm_2 (8), 3);
     195  }
     196  
     197  /**********************************************************************
     198   test_i386_basic_asm_3a/b: test of control flow: "asm goto"
     199   **********************************************************************/
     200  
     201  /* Create the equivalent of:
     202  
     203       int test_i386_basic_asm_3a (int p1, int p2)
     204       {
     205         asm goto ("btl %1, %0\n\t"
     206  		 "jc %l2"
     207  		 : // No outputs
     208  		 : "r" (p1), "r" (p2)
     209  		 : "cc"
     210  		 : carry);
     211  
     212         return 0;
     213  
     214        carry:
     215         return 1;
     216       }
     217  
     218      or (the "_3b" variant) using a name rather than a number for the goto
     219      label:
     220  
     221         // Quote from here in docs/topics/asm.rst: example 3b: C
     222         asm goto ("btl %1, %0\n\t"
     223                   "jc %l[carry]"
     224                   : // No outputs
     225                   : "r" (p1), "r" (p2)
     226                   : "cc"
     227                   : carry);
     228         // Quote up to here in docs/topics/asm.rst: example 3b: C
     229  
     230      This exercises control flow with an asm.  */
     231  
     232  static void
     233  create_test_i386_basic_asm_3 (gcc_jit_context *ctxt,
     234  			      const char *funcname,
     235  			      int use_name)
     236  {
     237    gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
     238    gcc_jit_param *p1 = gcc_jit_context_new_param (ctxt, NULL, int_type, "p1");
     239    gcc_jit_param *p2 = gcc_jit_context_new_param (ctxt, NULL, int_type, "p2");
     240    gcc_jit_param *params[2] = {p1, p2};
     241    gcc_jit_function *func
     242      = gcc_jit_context_new_function (ctxt, NULL,
     243  				    GCC_JIT_FUNCTION_EXPORTED,
     244  				    int_type,
     245  				    funcname,
     246  				    2, params, 0);
     247    gcc_jit_block *b_start = gcc_jit_function_new_block (func, "start");
     248    gcc_jit_block *b_fallthru = gcc_jit_function_new_block (func, "fallthru");
     249    gcc_jit_block *b_carry = gcc_jit_function_new_block (func, "carry");
     250  
     251    gcc_jit_rvalue *zero
     252      = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 0);
     253    gcc_jit_rvalue *one
     254      = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 1);
     255  
     256    /* Quote from here in docs/topics/asm.rst: example 3: jit.  */
     257    const char *asm_template =
     258      (use_name
     259       ? /* Label referred to by name: "%l[carry]".  */
     260         ("btl %1, %0\n\t"
     261          "jc %l[carry]")
     262       : /* Label referred to numerically: "%l2".  */
     263         ("btl %1, %0\n\t"
     264          "jc %l2"));
     265  
     266    gcc_jit_extended_asm *ext_asm
     267      = gcc_jit_block_end_with_extended_asm_goto (b_start, NULL,
     268  						asm_template,
     269  						1, &b_carry,
     270  						b_fallthru);
     271    gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
     272  					  gcc_jit_param_as_rvalue (p1));
     273    gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r",
     274  					  gcc_jit_param_as_rvalue (p2));
     275    gcc_jit_extended_asm_add_clobber (ext_asm, "cc");
     276    /* Quote up to here in docs/topics/asm.rst: example 3: jit.  */
     277  
     278    const char *desc = get_desc (ext_asm);
     279    CHECK_STRING_VALUE
     280      (desc,
     281       (use_name
     282        ? ("asm goto (\"btl %1, %0\\n\\tjc %l[carry]\" "
     283  	 ":  : \"r\" (p1), \"r\" (p2) : \"cc\" "
     284  	 ": carry [fallthrough: fallthru])")
     285        : ("asm goto (\"btl %1, %0\\n\\tjc %l2\" "
     286  	 ":  : \"r\" (p1), \"r\" (p2) : \"cc\" "
     287  	 ": carry [fallthrough: fallthru])")));
     288  
     289    gcc_jit_block_end_with_return (b_fallthru, NULL, zero);
     290    gcc_jit_block_end_with_return (b_carry, NULL, one);
     291  }
     292  
     293  static void
     294  verify_code_3 (gcc_jit_context *ctxt, gcc_jit_result *result,
     295  	       const char *funcname)
     296  {
     297    typedef int (*test_i386_basic_asm_3_type) (int, int);
     298  
     299    test_i386_basic_asm_3_type test_i386_basic_asm_3
     300      = (test_i386_basic_asm_3_type) gcc_jit_result_get_code (result, funcname);
     301    CHECK_NON_NULL (test_i386_basic_asm_3);
     302  
     303    /* The fn should test bits, returning 0 or 1.  */
     304    /* Bit 0.  */
     305    CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 0), 0);
     306    CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 0), 1);
     307    CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 0), 0);
     308    CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 0), 1);
     309    CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 0), 0);
     310    /* Bit 1.  */
     311    CHECK_VALUE (test_i386_basic_asm_3 (0x0000, 1), 0);
     312    CHECK_VALUE (test_i386_basic_asm_3 (0x0001, 1), 0);
     313    CHECK_VALUE (test_i386_basic_asm_3 (0x0002, 1), 1);
     314    CHECK_VALUE (test_i386_basic_asm_3 (0x0003, 1), 1);
     315    CHECK_VALUE (test_i386_basic_asm_3 (0x0004, 1), 0);
     316  
     317    for (int i = 0; i < 15; i++)
     318      {
     319        CHECK_VALUE (test_i386_basic_asm_3 (0x0000, i), 0);
     320        CHECK_VALUE (test_i386_basic_asm_3 (0xffff, i), 1);
     321      }
     322  }
     323  
     324  /**********************************************************************
     325   test_i386_basic_asm_4: test of "volatile"
     326   **********************************************************************/
     327  
     328  /* Create the equivalent of:
     329       uint64_t test_i386_basic_asm_4 (void)
     330       {
     331         uint64_t start_time, end_time;
     332  
     333         // Get start time
     334         asm volatile ("rdtsc\n\t"    // Returns the time in EDX:EAX.
     335                       "shl $32, %%rdx\n\t"  // Shift the upper bits left.
     336                       "or %%rdx, %0"        // 'Or' in the lower bits.
     337                       : "=a" (start_time)
     338                       :
     339                       : "rdx");
     340  
     341         // could do other work here
     342  
     343         // Get end time
     344         asm volatile ("rdtsc\n\t"    // Returns the time in EDX:EAX.
     345                       "shl $32, %%rdx\n\t"  // Shift the upper bits left.
     346                       "or %%rdx, %0"        // 'Or' in the lower bits.
     347                       : "=a" (start_time)
     348                       :
     349                       : "rdx");
     350  
     351         // Get elapsed time
     352         return end_time - start_time;
     353       }
     354  
     355     This exercises "volatile"; without it, the optimizer can assume that
     356     both asm generate the same value and thus the time difference is zero.  */
     357  
     358  static void
     359  add_rdtsc (gcc_jit_block *block, gcc_jit_lvalue *msr)
     360  {
     361    /* Quote from here in docs/topics/asm.rst: example 4: jit.  */
     362    gcc_jit_extended_asm *ext_asm
     363      = gcc_jit_block_add_extended_asm
     364  	(block, NULL,
     365  	 "rdtsc\n\t"  /* Returns the time in EDX:EAX.  */
     366  	 "shl $32, %%rdx\n\t"  /* Shift the upper bits left.  */
     367  	 "or %%rdx, %0");  /* 'Or' in the lower bits.  */
     368    gcc_jit_extended_asm_set_volatile_flag (ext_asm, 1);
     369    gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=a", msr);
     370    gcc_jit_extended_asm_add_clobber (ext_asm, "rdx");
     371    /* Quote up to here in docs/topics/asm.rst: example 4: jit.  */
     372  
     373    const char *desc = get_desc (ext_asm);
     374    CHECK_STRING_STARTS_WITH (desc, "asm volatile (");
     375  }
     376  
     377  static void
     378  create_test_i386_basic_asm_4 (gcc_jit_context *ctxt)
     379  {
     380    gcc_jit_type *uint64_type = gcc_jit_context_get_int_type (ctxt, 8, 0);
     381    gcc_jit_function *func
     382      = gcc_jit_context_new_function (ctxt, NULL,
     383  				    GCC_JIT_FUNCTION_EXPORTED,
     384  				    uint64_type,
     385  				    "test_i386_basic_asm_4",
     386  				    0, NULL, 0);
     387    gcc_jit_block *block = gcc_jit_function_new_block (func, NULL);
     388  
     389    gcc_jit_lvalue *start_time
     390      = gcc_jit_function_new_local (func, NULL, uint64_type, "start_time");
     391    add_rdtsc (block, start_time);
     392  
     393    gcc_jit_block_add_comment (block, NULL, "other work here");
     394  
     395    gcc_jit_lvalue *end_time
     396      = gcc_jit_function_new_local (func, NULL, uint64_type, "end_time");
     397    add_rdtsc (block, end_time);
     398  
     399    gcc_jit_rvalue *elapsed
     400      = gcc_jit_context_new_binary_op (ctxt, NULL, GCC_JIT_BINARY_OP_MINUS,
     401  				     uint64_type,
     402  				     gcc_jit_lvalue_as_rvalue (end_time),
     403  				     gcc_jit_lvalue_as_rvalue (start_time));
     404    gcc_jit_block_end_with_return (block, NULL, elapsed);
     405  }
     406  
     407  static void
     408  verify_code_4 (gcc_jit_context *ctxt, gcc_jit_result *result)
     409  {
     410    typedef uint64_t (*fntype) (void);
     411    fntype test_i386_basic_asm_4
     412      = (fntype)gcc_jit_result_get_code (result, "test_i386_basic_asm_4");
     413  
     414    CHECK_NON_NULL (test_i386_basic_asm_4);
     415  
     416    test_i386_basic_asm_4 ();
     417  }
     418  
     419  /**********************************************************************
     420   test_i386_basic_asm_5: test of top-level asm
     421   **********************************************************************/
     422  
     423  /* Create the equivalent of:
     424  
     425     // Quote from here in docs/topics/asm.rst: example 5: C
     426       asm ("\t.pushsection .text\n"
     427            "\t.globl add_asm\n"
     428            "\t.type add_asm, @function\n"
     429            "add_asm:\n"
     430            "\tmovq %rdi, %rax\n"
     431            "\tadd %rsi, %rax\n"
     432            "\tret\n"
     433            "\t.popsection\n");
     434     // Quote up to here in docs/topics/asm.rst: example 5: C
     435  
     436     to add a simple function ("add_asm") directly in assembly language.  */
     437  
     438  static void
     439  create_test_i386_basic_asm_5 (gcc_jit_context *ctxt)
     440  {
     441  #if __APPLE__
     442    /* Darwin's assemblers do not support push/pop section, do not use .type
     443       and external symbols should use __USER_LABEL_PREFIX__.  */
     444    gcc_jit_context_add_top_level_asm (ctxt, NULL,
     445                                       "\t.text\n"
     446                                       "\t.globl _add_asm\n"
     447                                       "_add_asm:\n"
     448                                       "\tmovq %rdi, %rax\n"
     449                                       "\tadd %rsi, %rax\n"
     450                                       "\tret\n"
     451                                       "\t# some asm here\n");
     452  #else
     453    /* Quote from here in docs/topics/asm.rst: example 5: jit.  */
     454    gcc_jit_context_add_top_level_asm (ctxt, NULL,
     455                                       "\t.pushsection .text\n"
     456                                       "\t.globl add_asm\n"
     457                                       "\t.type add_asm, @function\n"
     458                                       "add_asm:\n"
     459                                       "\tmovq %rdi, %rax\n"
     460                                       "\tadd %rsi, %rax\n"
     461                                       "\tret\n"
     462                                       "\t# some asm here\n"
     463                                       "\t.popsection\n");
     464    /* Quote up to here in docs/topics/asm.rst: example 5: jit.  */
     465  #endif
     466  }
     467  
     468  static void
     469  verify_code_5 (gcc_jit_context *ctxt, gcc_jit_result *result)
     470  {
     471    typedef int (*test_i386_basic_asm_5_type) (int, int);
     472    test_i386_basic_asm_5_type test_i386_basic_asm_5
     473      = (test_i386_basic_asm_5_type) gcc_jit_result_get_code (result, "add_asm");
     474    CHECK_NON_NULL (test_i386_basic_asm_5);
     475  
     476    CHECK_VALUE (test_i386_basic_asm_5 (2, 2), 4);
     477    CHECK_VALUE (test_i386_basic_asm_5 (20, 7), 27);
     478  }
     479  
     480  /**********************************************************************
     481   Code for harness
     482   **********************************************************************/
     483  
     484  void
     485  create_code (gcc_jit_context *ctxt, void *user_data)
     486  {
     487    create_test_i386_basic_asm_1 (ctxt);
     488    create_test_i386_basic_asm_2 (ctxt);
     489    create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3a", 0);
     490    create_test_i386_basic_asm_3 (ctxt, "test_i386_basic_asm_3b", 1);
     491    create_test_i386_basic_asm_4 (ctxt);
     492    create_test_i386_basic_asm_5 (ctxt);
     493  }
     494  
     495  void
     496  verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
     497  {
     498    CHECK_NON_NULL (result);
     499    verify_code_1 (ctxt, result);
     500    verify_code_2 (ctxt, result);
     501    verify_code_3 (ctxt, result, "test_i386_basic_asm_3a");
     502    verify_code_3 (ctxt, result, "test_i386_basic_asm_3b");
     503    verify_code_4 (ctxt, result);
     504    verify_code_5 (ctxt, result);
     505  }