100 lines
4.0 KiB
C
100 lines
4.0 KiB
C
#ifndef EMIT_H_
|
|
#define EMIT_H_
|
|
|
|
#define RAX "%rax"
|
|
#define EAX "%eax" // lowest 32 bits of %rax
|
|
#define AL "%al" // lowest byte of %rax
|
|
#define RBX "%rbx" // callee saved
|
|
#define RCX "%rcx"
|
|
#define RDX "%rdx"
|
|
#define RSP "%rsp" // callee saved
|
|
#define RBP "%rbp" // callee saved
|
|
#define RSI "%rsi"
|
|
#define RDI "%rdi"
|
|
#define R8 "%r8"
|
|
#define R9 "%r9"
|
|
#define R10 "%r10"
|
|
#define R11 "%r11"
|
|
#define R12 "%r12" // callee saved
|
|
#define R13 "%r13" // callee saved
|
|
#define R14 "%r14" // callee saved
|
|
#define R15 "%r15" // callee saved
|
|
#define RIP "%rip"
|
|
|
|
#define MEM(reg) "(" reg ")"
|
|
#define ARRAY_MEM(array, index, stride) "(" array "," index "," stride ")"
|
|
|
|
#define DIRECTIVE(fmt, ...) printf(fmt "\n" __VA_OPT__(, ) __VA_ARGS__)
|
|
#define LABEL(name, ...) printf(name ":\n" __VA_OPT__(, ) __VA_ARGS__)
|
|
#define EMIT(fmt, ...) printf("\t" fmt "\n" __VA_OPT__(, ) __VA_ARGS__)
|
|
|
|
#define MOVQ(src, dst) EMIT("movq %s, %s", (src), (dst))
|
|
#define MOVQ_IMM(imm, dst) EMIT("movq $%ld, %s", (int64_t)(imm), (dst))
|
|
#define MOVQ_OFFSET(offset, src, dst) EMIT("movq %d(%s), %s", (offset), (src), (dst))
|
|
#define PUSHQ(src) EMIT("pushq %s", (src))
|
|
#define POPQ(src) EMIT("popq %s", (src))
|
|
#define LEAQ_GLOBAL(name, dst) EMIT("leaq .%s(%%rip), %s", (name), (dst))
|
|
#define LEAQ_OFFSET(offset, src, dst) EMIT("leaq %d(%s), %s", (offset), (src), (dst))
|
|
#define STASH() MOVQ(RAX, RCX)
|
|
|
|
#define ADDQ(src, dst) EMIT("addq %s, %s", (src), (dst))
|
|
#define SUBQ(src, dst) EMIT("subq %s, %s", (src), (dst))
|
|
#define NEGQ(reg) EMIT("negq %s", (reg))
|
|
|
|
#define IMULQ(src, dst) EMIT("imulq %s, %s", (src), (dst))
|
|
#define CQO EMIT("cqo"); // Sign extend RAX -> RDX:RAX
|
|
#define IDIVQ(by) EMIT("idivq %s", (by)) // Divide RDX:RAX by "by", store result in RAX
|
|
|
|
#define RET EMIT("ret")
|
|
|
|
#define CMPQ(op1, op2) EMIT("cmpq %s, %s", (op1), (op2)) // Compare the two operands
|
|
|
|
// The SETcc-family of instructions assigns either 0 or 1 to a byte register, based on a comparison.
|
|
// The instruction immediately before the SETcc should be a
|
|
// cmpq op1, op2
|
|
// The suffix given to SET, the "cc" part of "setcc", is the "condition code".
|
|
// It determines the kind of comparison being done.
|
|
// If the comparison is true, 1 is stored into "byte_reg". Otherwise 0 is stored.
|
|
#define SETE(byte_reg) EMIT("sete %s", (byte_reg)) // Store result of op1 == op2
|
|
#define SETNE(byte_reg) EMIT("setne %s", (byte_reg)) // Store result of op1 != op2
|
|
// NOTE: for inequality checks, the order of CMPQ's operands is the opposite of what you expect
|
|
// The following inequalities are all for signed integer operands
|
|
#define SETG(byte_reg) EMIT("setg %s", (byte_reg)) // Store result of op2 > op1
|
|
#define SETGE(byte_reg) EMIT("setge %s", (byte_reg)) // Store result of op2 >= op1
|
|
#define SETL(byte_reg) EMIT("setl %s", (byte_reg)) // Store result of op2 < op1
|
|
#define SETLE(byte_reg) EMIT("setle %s", (byte_reg)) // Store result of op2 <= op1
|
|
|
|
// Since set*-instructions assign to a byte register, we must extend the byte to fill
|
|
// an entire 64-bit register, using movzbq (move Zero-extend Byte to Quadword).
|
|
#define MOVZBQ(byte_reg, full_reg) \
|
|
EMIT("movzbq %s, %s", (byte_reg), (full_reg)) // full_reg <- byte_reg
|
|
|
|
#define JNE(label) EMIT("jne %s", (label)) // Conditional jump (not equal)
|
|
#define JMP(label) EMIT("jmp %s", (label)) // Unconditional jump
|
|
|
|
// Bitwise and
|
|
#define ANDQ(src, dst) EMIT("andq %s, %s", (src), (dst))
|
|
|
|
// These directives are set based on platform,
|
|
// allowing the compiler to work on macOS as well.
|
|
// Section names are different,
|
|
// and exported and imported function labels start with _
|
|
#ifdef __APPLE__
|
|
#define ASM_BSS_SECTION "__DATA, __bss"
|
|
#define ASM_STRING_SECTION "__TEXT, __cstring"
|
|
#define ASM_DECLARE_SYMBOLS \
|
|
".set printf, _printf \n" \
|
|
".set putchar, _putchar \n" \
|
|
".set puts, _puts \n" \
|
|
".set strtol, _strtol \n" \
|
|
".set exit, _exit \n" \
|
|
".set _main, main \n" \
|
|
".global _main"
|
|
#else
|
|
#define ASM_BSS_SECTION ".bss"
|
|
#define ASM_STRING_SECTION ".rodata"
|
|
#define ASM_DECLARE_SYMBOLS ".global main"
|
|
#endif
|
|
|
|
#endif // EMIT_H_
|