Using Assembly Language with libgccjit#
libgccjit has some support for directly embedding assembler instructions.
This is based on GCC’s support for inline asm in C code, and the
following assumes a familiarity with that functionality. See
How to Use Inline Assembly Language in C Code
in GCC’s documentation, the “Extended Asm” section in particular.
These entrypoints were added in LIBGCCJIT_ABI_15; you can test for their presence using
#ifdef LIBGCCJIT_HAVE_ASM_STATEMENTS
Adding assembler instructions within a function#
-
type gcc_jit_extended_asm#
A gcc_jit_extended_asm represents an extended
asmstatement: a series of low-level instructions inside a function that convert inputs to outputs.To avoid having an API entrypoint with a very large number of parameters, an extended
asmstatement is made in stages: an initial call to create thegcc_jit_extended_asm, followed by calls to add operands and set other properties of the statement.There are two API entrypoints for creating a
gcc_jit_extended_asm:gcc_jit_block_add_extended_asm()for anasmstatement with no control flow, andgcc_jit_block_end_with_extended_asm_goto()for anasm goto.
For example, to create the equivalent of:
asm ("mov %1, %0\n\t" "add $1, %0" : "=r" (dst) : "r" (src));
the following API calls could be used:
gcc_jit_extended_asm *ext_asm = gcc_jit_block_add_extended_asm (block, NULL, "mov %1, %0\n\t" "add $1, %0"); gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst); gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", gcc_jit_lvalue_as_rvalue (src));
Warning
When considering the numbering of operands within an extended
asmstatement (e.g. the%0and%1above), the equivalent to the C syntax is followed i.e. all output operands, then all input operands, regardless of what order the calls togcc_jit_extended_asm_add_output_operand()andgcc_jit_extended_asm_add_input_operand()were made in.As in the C syntax, operands can be given symbolic names to avoid having to number them. For example, to create the equivalent of:
asm ("bsfl %[aMask], %[aIndex]" : [aIndex] "=r" (Index) : [aMask] "r" (Mask) : "cc");
the following API calls could be used:
gcc_jit_extended_asm *ext_asm = gcc_jit_block_add_extended_asm (block, NULL, "bsfl %[aMask], %[aIndex]"); gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index); gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r", gcc_jit_param_as_rvalue (mask)); gcc_jit_extended_asm_add_clobber (ext_asm, "cc");
-
gcc_jit_extended_asm *gcc_jit_block_add_extended_asm(gcc_jit_block *block, gcc_jit_location *loc, const char *asm_template)#
Create a
gcc_jit_extended_asmfor an extendedasmstatement with no control flow (i.e. without thegotoqualifier).The parameter
asm_templatecorresponds to the AssemblerTemplate within C’s extendedasmsyntax. It must be non-NULL. The call takes a copy of the underlying string, so it is valid to pass in a pointer to an on-stack buffer.
-
gcc_jit_extended_asm *gcc_jit_block_end_with_extended_asm_goto(gcc_jit_block *block, gcc_jit_location *loc, const char *asm_template, int num_goto_blocks, gcc_jit_block **goto_blocks, gcc_jit_block *fallthrough_block)#
Create a
gcc_jit_extended_asmfor an extendedasmstatement that may perform jumps, and use it to terminate the given block. This is equivalent to thegotoqualifier in C’s extendedasmsyntax.For example, to create the equivalent of:
asm goto ("btl %1, %0\n\t" "jc %l[carry]" : // No outputs : "r" (p1), "r" (p2) : "cc" : carry);
the following API calls could be used:
const char *asm_template = (use_name ? /* Label referred to by name: "%l[carry]". */ ("btl %1, %0\n\t" "jc %l[carry]") : /* Label referred to numerically: "%l2". */ ("btl %1, %0\n\t" "jc %l2")); gcc_jit_extended_asm *ext_asm = gcc_jit_block_end_with_extended_asm_goto (b_start, NULL, asm_template, 1, &b_carry, b_fallthru); gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", gcc_jit_param_as_rvalue (p1)); gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", gcc_jit_param_as_rvalue (p2)); gcc_jit_extended_asm_add_clobber (ext_asm, "cc");
here referencing a
gcc_jit_blocknamed “carry”.num_goto_blocksmust be >= 0.goto_blocksmust be non-NULL. This corresponds to theGotoLabelsparameter within C’s extendedasmsyntax. The block names can be referenced within the assembler template.fallthrough_blockcan be NULL. If non-NULL, it specifies the block to fall through to after the statement.Note
This is needed since each
gcc_jit_blockmust have a single exit point, as a basic block: you can’t jump from the middle of a block. A “goto” is implicitly added after the asm to handle the fallthrough case, which is equivalent to what would have happened in the C case.
-
void gcc_jit_extended_asm_set_volatile_flag(gcc_jit_extended_asm *ext_asm, int flag)#
Set whether the
gcc_jit_extended_asmhas side-effects, equivalent to the volatile qualifier in C’s extended asm syntax.For example, to create the equivalent of:
asm volatile ("rdtsc\n\t" // Returns the time in EDX:EAX. "shl $32, %%rdx\n\t" // Shift the upper bits left. "or %%rdx, %0" // 'Or' in the lower bits. : "=a" (msr) : : "rdx");
the following API calls could be used:
gcc_jit_extended_asm *ext_asm = gcc_jit_block_add_extended_asm (block, NULL, "rdtsc\n\t" /* Returns the time in EDX:EAX. */ "shl $32, %%rdx\n\t" /* Shift the upper bits left. */ "or %%rdx, %0"); /* 'Or' in the lower bits. */ gcc_jit_extended_asm_set_volatile_flag (ext_asm, 1); gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=a", msr); gcc_jit_extended_asm_add_clobber (ext_asm, "rdx");
where the
gcc_jit_extended_asmis flagged as volatile.
-
void gcc_jit_extended_asm_set_inline_flag(gcc_jit_extended_asm *ext_asm, int flag)#
Set the equivalent of the inline qualifier in C’s extended
asmsyntax.
-
void gcc_jit_extended_asm_add_output_operand(gcc_jit_extended_asm *ext_asm, const char *asm_symbolic_name, const char *constraint, gcc_jit_lvalue *dest)#
Add an output operand to the extended
asmstatement. See the Output Operands section of the documentation of the C syntax.asm_symbolic_namecorresponds to theasmSymbolicNamecomponent of C’s extendedasmsyntax. It can be NULL. If non-NULL it specifies the symbolic name for the operand.constraintcorresponds to theconstraintcomponent of C’s extendedasmsyntax. It must be non-NULL.destcorresponds to thecvariablenamecomponent of C’s extendedasmsyntax. It must be non-NULL.// Example with a NULL symbolic name, the equivalent of: // : "=r" (dst) gcc_jit_extended_asm_add_output_operand (ext_asm, NULL, "=r", dst); // Example with a symbolic name ("aIndex"), the equivalent of: // : [aIndex] "=r" (index) gcc_jit_extended_asm_add_output_operand (ext_asm, "aIndex", "=r", index);
This function can’t be called on an
asm gotoas such instructions can’t have outputs; see the Goto Labels section of GCC’s “Extended Asm” documentation.
-
void gcc_jit_extended_asm_add_input_operand(gcc_jit_extended_asm *ext_asm, const char *asm_symbolic_name, const char *constraint, gcc_jit_rvalue *src)#
Add an input operand to the extended
asmstatement. See the Input Operands section of the documentation of the C syntax.asm_symbolic_namecorresponds to theasmSymbolicNamecomponent of C’s extendedasmsyntax. It can be NULL. If non-NULL it specifies the symbolic name for the operand.constraintcorresponds to theconstraintcomponent of C’s extendedasmsyntax. It must be non-NULL.srccorresponds to thecexpressioncomponent of C’s extendedasmsyntax. It must be non-NULL.// Example with a NULL symbolic name, the equivalent of: // : "r" (src) gcc_jit_extended_asm_add_input_operand (ext_asm, NULL, "r", gcc_jit_lvalue_as_rvalue (src)); // Example with a symbolic name ("aMask"), the equivalent of: // : [aMask] "r" (Mask) gcc_jit_extended_asm_add_input_operand (ext_asm, "aMask", "r", gcc_jit_lvalue_as_rvalue (mask));
-
void gcc_jit_extended_asm_add_clobber(gcc_jit_extended_asm *ext_asm, const char *victim)#
Add victim to the list of registers clobbered by the extended
asmstatement. It must be non-NULL. See the Clobbers and Scratch Registers section of the documentation of the C syntax.Statements with multiple clobbers will require multiple calls, one per clobber.
For example:
gcc_jit_extended_asm_add_clobber (ext_asm, "r0"); gcc_jit_extended_asm_add_clobber (ext_asm, "cc"); gcc_jit_extended_asm_add_clobber (ext_asm, "memory");
A gcc_jit_extended_asm is a gcc_jit_object “owned” by
the block’s context. The following upcast is available:
-
gcc_jit_object *gcc_jit_extended_asm_as_object(gcc_jit_extended_asm *ext_asm)#
Upcast from extended
asmto object.
Adding top-level assembler statements#
In addition to creating extended asm instructions within a function,
there is support for creating “top-level” assembler statements, outside
of any function.
-
void gcc_jit_context_add_top_level_asm(gcc_jit_context *ctxt, gcc_jit_location *loc, const char *asm_stmts)#
Create a set of top-level asm statements, analogous to those created by GCC’s “basic”
asmsyntax in C at file scope.For example, to create the equivalent of:
asm ("\t.pushsection .text\n" "\t.globl add_asm\n" "\t.type add_asm, @function\n" "add_asm:\n" "\tmovq %rdi, %rax\n" "\tadd %rsi, %rax\n" "\tret\n" "\t.popsection\n");
the following API calls could be used:
gcc_jit_context_add_top_level_asm (ctxt, NULL, "\t.pushsection .text\n" "\t.globl add_asm\n" "\t.type add_asm, @function\n" "add_asm:\n" "\tmovq %rdi, %rax\n" "\tadd %rsi, %rax\n" "\tret\n" "\t# some asm here\n" "\t.popsection\n");