From 7fc4ed4907e907ce6f04b38a91d4ff6b661d8766 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 20 Apr 2024 16:50:59 +0900 Subject: [PATCH 01/25] Output local symbol Output symbols in order: * local * global --- src/as/as.c | 82 +++++++++++++++++++++++++++++++--------------- src/as/ir_asm.h | 5 +-- src/util/elfutil.c | 35 ++++++++++++++++---- src/util/elfutil.h | 2 ++ 4 files changed, 90 insertions(+), 34 deletions(-) diff --git a/src/as/as.c b/src/as/as.c index 5df4fc9a4..6e696af70 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -22,6 +22,18 @@ #define LOAD_ADDRESS START_ADDRESS #define DATA_ALIGN (0x1000) +static LabelInfo *make_label_referred(Table *label_table, const Name *label, bool und) { + LabelInfo *label_info = table_get(label_table, label); + if (label_info == NULL) { + if (!und) + return NULL; + const int SEC_UND = -1; + label_info = add_label_table(label_table, label, SEC_UND, false, true); + } + label_info->flag |= LF_REFERRED; + return label_info; +} + static void parse_file(FILE *fp, const char *filename, Vector **section_irs, Table *label_table) { ParseInfo info; info.filename = filename; @@ -85,7 +97,16 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { // Construct symtab and strtab. Symtab symtab; symtab_init(&symtab); + int local_symbol_count; { + Symtab symtab_global; + symtab_init(&symtab_global); + + Symtab *symtabs[] = { + [STB_LOCAL] = &symtab, + [STB_GLOBAL] = &symtab_global, + }; + // UND Elf64_Sym *sym; sym = symtab_add(&symtab, alloc_name("", NULL, false)); @@ -97,23 +118,33 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { sym->st_shndx = i + 1; // Section index. } - // Label symbols + const int UND_INDEX = 0; const Name *name; LabelInfo *info; for (int it = 0; (it = table_iterate(label_table, it, &name, (void**)&info)) != -1; ) { - if (!(info->flag & LF_GLOBAL) || !(info->flag & LF_DEFINED)) + int bind; + if (info->flag & LF_GLOBAL) { + bind = STB_GLOBAL; + } else if (info->flag & LF_REFERRED) { + bind = STB_LOCAL; + } else { continue; - sym = symtab_add(&symtab, name); + } + sym = symtab_add(symtabs[bind], name); int type; switch (info->kind) { case LK_NONE: type = STT_NOTYPE; break; case LK_FUNC: type = STT_FUNC; break; case LK_OBJECT: type = STT_OBJECT; break; } - sym->st_info = ELF64_ST_INFO(STB_GLOBAL, type); - sym->st_value = info->address - section_start_addresses[info->section]; - sym->st_shndx = info->section + 1; // Symbol index for Local section. + sym->st_info = ELF64_ST_INFO(bind, type); + sym->st_value = (info->flag & LF_DEFINED) ? info->address - section_start_addresses[info->section] : 0; + sym->st_shndx = info->section >= 0 ? info->section + 1 : UND_INDEX; // Symbol index for Local section. } + + local_symbol_count = symtab.count; + // Append global symbols after locals; + symtab_concat(&symtab, &symtab_global); } FILE *ofp; @@ -185,13 +216,12 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { case UNRES_EXTERN: case UNRES_EXTERN_PC32: { - Elf64_Sym *sym = symtab_add(&symtab, u->label); - sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_NOTYPE); - size_t index = sym - symtab.buf; + int symidx = symtab_find(&symtab, u->label); + assert(symidx >= 0); rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(index, u->kind == UNRES_EXTERN_PC32 ? R_X86_64_PC32 - : R_X86_64_PLT32); + rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_EXTERN_PC32 ? R_X86_64_PC32 + : R_X86_64_PLT32); rela->r_addend = u->add; } break; @@ -199,10 +229,9 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { { LabelInfo *label = table_get(label_table, u->label); assert(label != NULL); - // Symtab index for .rodata section = section number + 1 - int rodata_index = label->section + 1; + int secidx = label->section + 1; rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(rodata_index, R_X86_64_PC32); + rela->r_info = ELF64_R_INFO(secidx, R_X86_64_PC32); rela->r_addend = u->add; } break; @@ -210,12 +239,11 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { { LabelInfo *label = table_get(label_table, u->label); if (label == NULL || label->flag & LF_GLOBAL) { - Elf64_Sym *sym = symtab_add(&symtab, u->label); - sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_NOTYPE); - size_t index = sym - symtab.buf; + int symidx = symtab_find(&symtab, u->label); + assert(symidx >= 0); rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(index, R_X86_64_64); + rela->r_info = ELF64_R_INFO(symidx, R_X86_64_64); rela->r_addend = u->add; } else { rela->r_offset = u->offset; @@ -226,20 +254,16 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { break; case UNRES_RISCV_CALL: { - Elf64_Sym *sym = symtab_add(&symtab, u->label); - sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_NOTYPE); - size_t index = sym - symtab.buf; + int symidx = symtab_find(&symtab, u->label); + assert(symidx >= 0); rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(index, R_RISCV_CALL); + rela->r_info = ELF64_R_INFO(symidx, R_RISCV_CALL); rela->r_addend = u->add; } break; case UNRES_RISCV_RELAX: { - Elf64_Sym *sym = symtab_add(&symtab, u->label); - sym->st_info = ELF64_ST_INFO(STB_GLOBAL, STT_NOTYPE); - rela->r_offset = u->offset; rela->r_info = ELF64_R_INFO(0, R_RISCV_RELAX); rela->r_addend = u->add; @@ -380,7 +404,7 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { .sh_offset = symtab_ofs, .sh_size = sizeof(*symtab.buf) * symtab.count, .sh_link = 8, // Index of strtab - .sh_info = 5, // Number of local symbols + .sh_info = local_symbol_count, // Number of local symbols .sh_addralign = 8, .sh_entsize = sizeof(Elf64_Sym), }; @@ -489,6 +513,12 @@ int main(int argc, char *argv[]) { settle1 = calc_label_address(LOAD_ADDRESS, section_irs, &label_table); settle2 = resolve_relative_address(section_irs, &label_table, unresolved); } while (!(settle1 && settle2)); + + for (int i = 0; i < unresolved->len; ++i) { + UnresolvedInfo *u = unresolved->data[i]; + make_label_referred(&label_table, u->label, true); + } + emit_irs(section_irs); fix_section_size(LOAD_ADDRESS); diff --git a/src/as/ir_asm.h b/src/as/ir_asm.h index 11df49f73..5f338e6f0 100644 --- a/src/as/ir_asm.h +++ b/src/as/ir_asm.h @@ -12,8 +12,9 @@ typedef struct Name Name; typedef struct Table Table; typedef struct Vector Vector; -#define LF_GLOBAL (1 << 0) -#define LF_DEFINED (1 << 1) +#define LF_GLOBAL (1 << 0) +#define LF_DEFINED (1 << 1) +#define LF_REFERRED (1 << 2) enum LabelKind { LK_NONE, diff --git a/src/util/elfutil.c b/src/util/elfutil.c index 9fd4ca4ef..ba632f0a9 100644 --- a/src/util/elfutil.c +++ b/src/util/elfutil.c @@ -3,6 +3,7 @@ #ifndef ELF_NOT_SUPPORTED +#include #include #include // realloc #include // memcpy @@ -48,15 +49,19 @@ void symtab_init(Symtab *symtab) { symtab->count = 0; } +int symtab_find(Symtab *symtab, const Name *name) { + intptr_t index; + if (table_try_get(&symtab->indices, name, (void**)&index)) + return index; + return -1; +} + Elf64_Sym *symtab_add(Symtab *symtab, const Name *name) { uint32_t offset = strtab_add(&symtab->strtab, name); if (name->bytes > 0) { - for (int i = 0; i < symtab->count; ++i) { - uintptr_t index; - if (table_try_get(&symtab->indices, name, (void**)&index)) { - return &symtab->buf[index]; - } - } + int index = symtab_find(symtab, name); + if (index >= 0) + return &symtab->buf[index]; } int old_count = symtab->count; @@ -70,6 +75,24 @@ Elf64_Sym *symtab_add(Symtab *symtab, const Name *name) { return sym; } +void symtab_concat(Symtab *dest, Symtab *src) { + int n = src->count; + const Name **names = alloca(sizeof(*names) * n); + const Name *name; + intptr_t index; + for (int it = 0; (it = table_iterate(&src->indices, it, &name, (void**)&index)) != -1; ) { + assert(index < n); + names[index] = name; + } + for (int i = 0; i < n; ++i) { + const Name *name = names[i]; + Elf64_Sym *p = symtab_add(dest, name); + Elf64_Word st_name_bak = p->st_name; + memcpy(p, &src->buf[i], sizeof(*p)); + p->st_name = st_name_bak; + } +} + // void out_elf_header(FILE *fp, uintptr_t entry, int phnum, int shnum, int flags) { diff --git a/src/util/elfutil.h b/src/util/elfutil.h index 4ab2027e4..d73ffcb8e 100644 --- a/src/util/elfutil.h +++ b/src/util/elfutil.h @@ -33,7 +33,9 @@ typedef struct { } Symtab; void symtab_init(Symtab *symtab); +int symtab_find(Symtab *symtab, const Name *name); Elf64_Sym *symtab_add(Symtab *symtab, const Name *name); +void symtab_concat(Symtab *dest, Symtab *src); // From 4864fb64d0f85b7de1a831d2b6b821facba14b41 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 20 Apr 2024 08:32:37 +0900 Subject: [PATCH 02/25] Fix parsing register name Reject if label character is followed. --- src/as/arch/aarch64/parse_aarch64.c | 2 +- src/as/arch/riscv64/parse_riscv64.c | 2 +- src/as/arch/x64/parse_x64.c | 2 +- src/as/parse_asm.c | 4 ++-- src/as/parse_asm.h | 3 +++ 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index 5ff3fb97f..6baff0d37 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -125,7 +125,7 @@ static enum RegType find_register(const char **pp) { for (int i = 0; i < (int)ARRAY_SIZE(kRegisters); ++i) { const char *name = kRegisters[i].name; size_t n = strlen(name); - if (strncmp(p, name, n) == 0 && !isdigit(p[n])) { + if (strncmp(p, name, n) == 0 && !is_label_chr(p[n])) { *pp = p + n; return kRegisters[i].reg; } diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 8eecf6020..ff3714da1 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -152,7 +152,7 @@ static enum RegType find_register(const char **pp) { for (int i = 0; i < (int)ARRAY_SIZE(kRegisters); ++i) { const char *name = kRegisters[i].name; size_t n = strlen(name); - if (strncmp(p, name, n) == 0) { + if (strncmp(p, name, n) == 0 && !is_label_chr(p[n])) { *pp = p + n; return kRegisters[i].reg; } diff --git a/src/as/arch/x64/parse_x64.c b/src/as/arch/x64/parse_x64.c index 0a20bddcb..88fb6c946 100644 --- a/src/as/arch/x64/parse_x64.c +++ b/src/as/arch/x64/parse_x64.c @@ -155,7 +155,7 @@ static enum RegType find_register(const char **pp) { for (int i = 0; i < (int)ARRAY_SIZE(kRegisters); ++i) { const char *name = kRegisters[i].name; size_t n = strlen(name); - if (strncmp(p, name, n) == 0) { + if (strncmp(p, name, n) == 0 && !is_label_chr(p[n])) { *pp = p + n; return kRegisters[i].reg; } diff --git a/src/as/parse_asm.c b/src/as/parse_asm.c index dc127201e..9bec1c45a 100644 --- a/src/as/parse_asm.c +++ b/src/as/parse_asm.c @@ -88,11 +88,11 @@ bool immediate(const char **pp, int64_t *value) { return true; } -inline bool is_label_first_chr(char c) { +bool is_label_first_chr(char c) { return isalpha(c) || c == '_' || c == '.'; } -inline bool is_label_chr(char c) { +bool is_label_chr(char c) { return is_label_first_chr(c) || isdigit(c); } diff --git a/src/as/parse_asm.h b/src/as/parse_asm.h index 29cc90580..97f460694 100644 --- a/src/as/parse_asm.h +++ b/src/as/parse_asm.h @@ -101,3 +101,6 @@ typedef struct { } Value; Value calc_expr(Table *label_table, const Expr *expr); + +bool is_label_first_chr(char c); +bool is_label_chr(char c); From ec4ec6853c6806d7f3ef93cf6f44fc4fafc4b429 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Fri, 12 Apr 2024 21:20:40 +0900 Subject: [PATCH 03/25] Handle string address * Insert label for `LA` instruction, and stored into `opr3` * Local symbols should be arranged first, then global in ELF format --- include/elf.h | 6 ++-- src/as/arch/aarch64/parse_aarch64.c | 3 +- src/as/arch/riscv64/asm_code.c | 22 +++++++++---- src/as/arch/riscv64/inst.h | 3 +- src/as/arch/riscv64/ir_asm.c | 50 +++++++++++++++++++++++++++-- src/as/arch/riscv64/parse_riscv64.c | 43 +++++++++++++++++++++---- src/as/arch/x64/parse_x64.c | 3 +- src/as/as.c | 11 +++++++ src/as/ir_asm.h | 2 ++ src/as/parse_asm.c | 8 ++--- src/as/parse_asm.h | 3 +- 11 files changed, 129 insertions(+), 25 deletions(-) diff --git a/include/elf.h b/include/elf.h index a9478a3e9..0b0913755 100644 --- a/include/elf.h +++ b/include/elf.h @@ -147,8 +147,10 @@ typedef struct { #define R_X86_64_PC32 (2) /* PC relative 32 bit signed */ #define R_X86_64_PLT32 (4) /* 32 bit PLT address */ -#define R_RISCV_CALL (18) -#define R_RISCV_RELAX (51) +#define R_RISCV_CALL (18) +#define R_RISCV_PCREL_HI20 (23) +#define R_RISCV_PCREL_LO12_I (24) +#define R_RISCV_RELAX (51) #define ELF64_R_SYM(info) ((info) >> 32) #define ELF64_R_TYPE(info) ((Elf64_Word)(info)) diff --git a/src/as/arch/aarch64/parse_aarch64.c b/src/as/arch/aarch64/parse_aarch64.c index 6baff0d37..c259763e5 100644 --- a/src/as/arch/aarch64/parse_aarch64.c +++ b/src/as/arch/aarch64/parse_aarch64.c @@ -167,7 +167,8 @@ static bool parse_operand(ParseInfo *info, Operand *operand) { return false; } -void parse_inst(ParseInfo *info, Inst *inst) { +void parse_inst(ParseInfo *info, Line *line) { + Inst *inst = &line->inst; Operand *opr_table[] = {&inst->opr1, &inst->opr2, &inst->opr3}; for (int i = 0; i < (int)ARRAY_SIZE(opr_table); ++i) opr_table[i]->type = NOOPERAND; diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 0d8fbe513..1d8fffdf7 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -61,13 +61,13 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define UTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 31, 12) << 12) | ((rd) << 7) | (opcode)) // U-type #define JTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 20, 20) << 31) | (IMM(imm, 10, 1) << 20) | (IMM(imm, 11, 11) << 19) | (IMM(imm, 19, 12) << 12) | ((rd) << 7) | (opcode)) // J-type -#define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | (rd << 7) | (IMM(imm, 4, 0) << 2)) -#define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 5, 5) << 12) | (rd << 7) | (IMM(imm, 4, 0) << 2)) -#define C_ADDI(rd, imm) MAKE_CODE16(inst, code, 0x0001 | (IMM(imm, 5, 5) << 12) | (rd << 7) | (IMM(imm, 4, 0) << 2)) -#define C_ADDIW(rd, imm) MAKE_CODE16(inst, code, 0x2001 | (IMM(imm, 5, 5) << 12) | (rd << 7) | (IMM(imm, 4, 0) << 2)) -#define C_LDSP(rd, imm) MAKE_CODE16(inst, code, 0x6002 | (IMM(imm, 5, 5) << 12) | (rd << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) -#define C_SDSP(rs, imm) MAKE_CODE16(inst, code, 0xe002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | (rs << 2)) -#define C_JR(rs) MAKE_CODE16(inst, code, 0x8002 | (rs << 7)) +#define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_ADDI(rd, imm) MAKE_CODE16(inst, code, 0x0001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_ADDIW(rd, imm) MAKE_CODE16(inst, code, 0x2001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_LDSP(rd, imm) MAKE_CODE16(inst, code, 0x6002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) +#define C_SDSP(rs, imm) MAKE_CODE16(inst, code, 0xe002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) +#define C_JR(rs) MAKE_CODE16(inst, code, 0x8002 | ((rs) << 7)) #define ADDI(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x13) #define ADDIW(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x1b) @@ -105,6 +105,13 @@ static unsigned char *asm_li(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_la(Inst *inst, Code *code) { + int rd = inst->opr1.reg.no; + AUIPC(rd, 0); + ADDI(rd, rd, 0); + return code->buf; +} + static unsigned char *asm_addi(Inst *inst, Code *code) { int rd = inst->opr1.reg.no; int rs = inst->opr2.reg.no; @@ -172,6 +179,7 @@ typedef struct { static const AsmInstTable *table[] = { [NOOP] = (const AsmInstTable[]){ {asm_noop, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, [LI] = (const AsmInstTable[]){ {asm_li, REG, IMMEDIATE, NOOPERAND}, {NULL} }, + [LA] = (const AsmInstTable[]){ {asm_la, REG, DIRECT, DIRECT}, {NULL} }, [ADDI] = (const AsmInstTable[]){ {asm_addi, REG, REG, IMMEDIATE}, {NULL} }, [LD] = (const AsmInstTable[]){ {asm_ld, REG, INDIRECT, NOOPERAND}, {NULL} }, [SD] = (const AsmInstTable[]){ {asm_sd, REG, INDIRECT, NOOPERAND}, {NULL} }, diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 3fa47115f..94f2ec024 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -10,6 +10,7 @@ typedef struct Expr Expr; enum Opcode { NOOP, LI, + LA, ADDI, LD, SD, @@ -32,7 +33,7 @@ enum OperandType { NOOPERAND, REG, // reg IMMEDIATE, // 1234 - DIRECT, // foobar + DIRECT, // foobar + 345 INDIRECT, // ofs(reg) }; diff --git a/src/as/arch/riscv64/ir_asm.c b/src/as/arch/riscv64/ir_asm.c index 2ea2c3d22..3dcfe295f 100644 --- a/src/as/arch/riscv64/ir_asm.c +++ b/src/as/arch/riscv64/ir_asm.c @@ -168,12 +168,58 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * { Inst *inst = ir->code.inst; switch (inst->op) { + case LA: + assert(inst->opr3.type == DIRECT); + if (inst->opr2.type == DIRECT) { + Value value = calc_expr(label_table, inst->opr2.direct.expr); + if (value.label != NULL) { + uintptr_t offset = address - start_address; + UnresolvedInfo *info; + info = calloc_or_die(sizeof(*info)); + info->kind = UNRES_RISCV_PCREL_HI20; + info->label = value.label; + info->src_section = sec; + info->offset = offset; + info->add = value.offset; + vec_push(unresolved, info); + + info = calloc_or_die(sizeof(*info)); + info->kind = UNRES_RISCV_RELAX; + info->label = value.label; + info->src_section = sec; + info->offset = offset; + info->add = value.offset; + vec_push(unresolved, info); + + // hilabel points to AUIPC instruction, just above one. + assert(inst->opr3.direct.expr->kind == EX_LABEL); + const Name *hilabel = inst->opr3.direct.expr->label; + info = calloc_or_die(sizeof(*info)); + info->kind = UNRES_RISCV_PCREL_LO12_I; + info->label = hilabel; + info->src_section = sec; + info->offset = offset + 4; + info->add = 0; + vec_push(unresolved, info); + + info = calloc_or_die(sizeof(*info)); + info->kind = UNRES_RISCV_RELAX; + info->label = hilabel; + info->src_section = sec; + info->offset = offset + 4; + info->add = 0; + vec_push(unresolved, info); + break; + } + } + break; case CALL: if (inst->opr1.type == DIRECT) { Value value = calc_expr(label_table, inst->opr1.direct.expr); if (value.label != NULL) { // Put rela even if the label is defined in the same object file. - UnresolvedInfo *info = malloc_or_die(sizeof(*info)); + UnresolvedInfo *info; + info = calloc_or_die(sizeof(*info)); info->kind = UNRES_RISCV_CALL; info->label = value.label; info->src_section = sec; @@ -181,7 +227,7 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * info->add = value.offset; vec_push(unresolved, info); - info = malloc_or_die(sizeof(*info)); + info = calloc_or_die(sizeof(*info)); info->kind = UNRES_RISCV_RELAX; info->label = value.label; info->src_section = sec; diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index ff3714da1..52065101e 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -6,11 +6,13 @@ #include #include +#include "table.h" #include "util.h" // Align with Opcode. static const char *kOpTable[] = { "li", + "la", "addi", "ld", "sd", @@ -201,17 +203,25 @@ static bool parse_operand(ParseInfo *info, Operand *operand) { operand->immediate = expr->fixnum; return true; } - if (expr->kind == EX_LABEL) { - operand->type = DIRECT; - operand->direct.expr = expr; - return true; - } + operand->type = DIRECT; + operand->direct.expr = expr; + return true; } return false; } -void parse_inst(ParseInfo *info, Inst *inst) { +static const Name *alloc_dummy_label(void) { + // TODO: Ensure label is unique. + static int label_no; + ++label_no; + char buf[2 + sizeof(int) * 3 + 1]; + snprintf(buf, sizeof(buf), "._%d", label_no); + return alloc_name(buf, NULL, true); +} + +void parse_inst(ParseInfo *info, Line *line) { + Inst *inst = &line->inst; Operand *opr_table[] = {&inst->opr1, &inst->opr2, &inst->opr3}; for (int i = 0; i < (int)ARRAY_SIZE(opr_table); ++i) opr_table[i]->type = NOOPERAND; @@ -228,4 +238,25 @@ void parse_inst(ParseInfo *info, Inst *inst) { info->p = skip_whitespaces(info->p + 1); } } + + // Tweak for instruction. + switch (inst->op) { + case LA: + // Store corresponding label to opr3. + if (line->label == NULL) { + // Generate unique label. + const Name *label = alloc_dummy_label(); + line->label = label; + } + if (inst->opr3.type == NOOPERAND) { + Expr *expr = new_expr(EX_LABEL); + expr->label = line->label; + + Operand *opr = &inst->opr3; + opr->type = DIRECT; + opr->direct.expr = expr; + } + break; + default: break; + } } diff --git a/src/as/arch/x64/parse_x64.c b/src/as/arch/x64/parse_x64.c index 88fb6c946..3fc0c8c79 100644 --- a/src/as/arch/x64/parse_x64.c +++ b/src/as/arch/x64/parse_x64.c @@ -416,7 +416,8 @@ static bool parse_operand(ParseInfo *info, Operand *operand) { return false; } -void parse_inst(ParseInfo *info, Inst *inst) { +void parse_inst(ParseInfo *info, Line *line) { + Inst *inst = &line->inst; Operand *opr_table[] = {&inst->src, &inst->dst}; for (int i = 0; i < (int)ARRAY_SIZE(opr_table); ++i) opr_table[i]->type = NOOPERAND; diff --git a/src/as/as.c b/src/as/as.c index 6e696af70..8c2f6cae9 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -269,6 +269,17 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { rela->r_addend = u->add; } break; + case UNRES_RISCV_PCREL_HI20: + case UNRES_RISCV_PCREL_LO12_I: + { + int symidx = symtab_find(&symtab, u->label); + assert(symidx >= 0); + + rela->r_offset = u->offset; + rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_RISCV_PCREL_HI20 ? R_RISCV_PCREL_HI20 : R_RISCV_PCREL_LO12_I); + rela->r_addend = u->add; + } + break; } } diff --git a/src/as/ir_asm.h b/src/as/ir_asm.h index 5f338e6f0..11301ebd1 100644 --- a/src/as/ir_asm.h +++ b/src/as/ir_asm.h @@ -39,6 +39,8 @@ enum UnresolvedKind { UNRES_RISCV_CALL, UNRES_RISCV_RELAX, + UNRES_RISCV_PCREL_HI20, + UNRES_RISCV_PCREL_LO12_I, }; typedef struct { diff --git a/src/as/parse_asm.c b/src/as/parse_asm.c index 9bec1c45a..e7132121e 100644 --- a/src/as/parse_asm.c +++ b/src/as/parse_asm.c @@ -322,7 +322,7 @@ static const Token *match(ParseInfo *info, enum TokenKind kind) { return token; } -static Expr *new_expr(enum ExprKind kind) { +Expr *new_expr(enum ExprKind kind) { Expr *expr = malloc_or_die(sizeof(*expr)); expr->kind = kind; return expr; @@ -504,7 +504,7 @@ Line *parse_line(ParseInfo *info) { info->p = r; } else if (*p != '\0') { info->p = p; - parse_inst(info, &line->inst); + parse_inst(info, line); check_line_end(info); } } @@ -648,11 +648,11 @@ void handle_directive(ParseInfo *info, enum DirectiveType dir, Vector **section_ { const Name *label = parse_label(info); if (label == NULL) { - parse_error(info, ".comm: label expected"); + parse_error(info, ".type: label expected"); break; } if (*info->p != ',') { - parse_error(info, ".comm: `,' expected"); + parse_error(info, ".type: `,' expected"); break; } info->p = skip_whitespaces(info->p + 1); diff --git a/src/as/parse_asm.h b/src/as/parse_asm.h index 97f460694..83a7271a2 100644 --- a/src/as/parse_asm.h +++ b/src/as/parse_asm.h @@ -89,11 +89,12 @@ Line *parse_line(ParseInfo *info); void handle_directive(ParseInfo *info, enum DirectiveType dir, Vector **section_irs, Table *label_table); void parse_error(const ParseInfo *info, const char *message); -void parse_inst(ParseInfo *info, Inst *inst); +void parse_inst(ParseInfo *info, Line *line); bool immediate(const char **pp, int64_t *value); const Name *unquote_label(const char *p, const char *q); Expr *parse_expr(ParseInfo *info); +Expr *new_expr(enum ExprKind kind); typedef struct { const Name *label; From 1e2afb91e734f2d48c9adaa749a8a2200648a914 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Thu, 18 Apr 2024 16:41:15 +0900 Subject: [PATCH 04/25] Load/store instructions --- src/as/arch/riscv64/asm_code.c | 160 ++++++++++++++++++++++------ src/as/arch/riscv64/inst.h | 5 +- src/as/arch/riscv64/parse_riscv64.c | 5 +- 3 files changed, 132 insertions(+), 38 deletions(-) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 1d8fffdf7..b5cd1b10d 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -61,22 +61,39 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define UTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 31, 12) << 12) | ((rd) << 7) | (opcode)) // U-type #define JTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 20, 20) << 31) | (IMM(imm, 10, 1) << 20) | (IMM(imm, 11, 11) << 19) | (IMM(imm, 19, 12) << 12) | ((rd) << 7) | (opcode)) // J-type -#define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_ADDI(rd, imm) MAKE_CODE16(inst, code, 0x0001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_ADDIW(rd, imm) MAKE_CODE16(inst, code, 0x2001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_LDSP(rd, imm) MAKE_CODE16(inst, code, 0x6002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) -#define C_SDSP(rs, imm) MAKE_CODE16(inst, code, 0xe002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) -#define C_JR(rs) MAKE_CODE16(inst, code, 0x8002 | ((rs) << 7)) - -#define ADDI(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x13) -#define ADDIW(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x1b) -#define AUIPC(rd, imm) UTYPE(imm, rd, 0x17) -#define JALR(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x67) -#define RET() C_JR(RA) - -#define LI(rd, imm) ADDI(rd, ZERO, imm) -#define MV(rd, rs) ADDI(rd, rs, 0) +#define W_ADDI(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x13) +#define W_ADDIW(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x1b) +#define W_LB(rd, ofs, rs) ITYPE(ofs, rs, 0x00, rd, 0x03) +#define W_LH(rd, ofs, rs) ITYPE(ofs, rs, 0x01, rd, 0x03) +#define W_LW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x03) +#define W_LD(rd, ofs, rs) ITYPE(ofs, rs, 0x03, rd, 0x03) +#define W_LBU(rd, ofs, rs) ITYPE(ofs, rs, 0x04, rd, 0x03) +#define W_LHU(rd, ofs, rs) ITYPE(ofs, rs, 0x05, rd, 0x03) +#define W_LWU(rd, ofs, rs) ITYPE(ofs, rs, 0x06, rd, 0x03) +#define W_SB(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x00, 0x23) +#define W_SH(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x01, 0x23) +#define W_SW(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x02, 0x23) +#define W_SD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x23) +#define W_AUIPC(rd, imm) UTYPE(imm, rd, 0x17) +#define W_JALR(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x67) + +#define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_ADDI(rd, imm) MAKE_CODE16(inst, code, 0x0001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_ADDIW(rd, imm) MAKE_CODE16(inst, code, 0x2001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_LW(rd, imm, rs) MAKE_CODE16(inst, code, 0x4000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 2, 2) << 6) | (IMM(imm, 6, 6) << 5) | (to_rvc_reg(rd) << 2)) +#define C_LD(rd, imm, rs) MAKE_CODE16(inst, code, 0x6000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rd) << 2)) +#define C_SW(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xc000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rs2) << 2)) +#define C_SD(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xe000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rs2) << 2)) +#define C_LDSP(rd, imm) MAKE_CODE16(inst, code, 0x6002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) +#define C_SDSP(rs, imm) MAKE_CODE16(inst, code, 0xe002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) +#define C_JR(rs) MAKE_CODE16(inst, code, 0x8002 | ((rs) << 7)) + +#define P_RET() C_JR(RA) +#define P_LI(rd, imm) W_ADDI(rd, ZERO, imm) + +extern inline bool is_rvc_reg(int reg) { return reg >= 8 && reg <= 15; } // X8~X15 +extern inline int to_rvc_reg(int reg) { return reg - 8; } static unsigned char *asm_noop(Inst *inst, Code *code) { UNUSED(inst); @@ -90,14 +107,14 @@ static unsigned char *asm_li(Inst *inst, Code *code) { if (is_im6(imm)) { C_LI(rd, imm); } else if (is_im12(imm)) { - LI(rd, imm); + P_LI(rd, imm); } else if (is_im18(imm)) { int h = imm >> 12, l = imm & 0xfff; C_LUI(rd, h); if (is_im6(imm)) C_ADDIW(rd, l); else - ADDIW(rd, rd, l); + W_ADDIW(rd, rd, l); } else { // TODO: return NULL; @@ -107,8 +124,8 @@ static unsigned char *asm_li(Inst *inst, Code *code) { static unsigned char *asm_la(Inst *inst, Code *code) { int rd = inst->opr1.reg.no; - AUIPC(rd, 0); - ADDI(rd, rd, 0); + W_AUIPC(rd, 0); + W_ADDI(rd, rd, 0); return code->buf; } @@ -129,25 +146,91 @@ static unsigned char *asm_ld(Inst *inst, Code *code) { int rd = inst->opr1.reg.no; Expr *offset = inst->opr2.indirect.offset; if (offset == NULL || offset->kind == EX_FIXNUM) { - int64_t imm = offset != NULL ? offset->fixnum : 0; - int base_reg = inst->opr2.indirect.reg.no; - if (imm >= 0 && imm < (1 << 9) && (imm & 7) == 0 && base_reg == SP) { - C_LDSP(rd, imm); + int64_t ofs = offset != NULL ? offset->fixnum : 0; + int rs = inst->opr2.indirect.reg.no; + switch (inst->op) { + case LB: + // TODO: Check offset range. + W_LB(rd, ofs, rs); + return code->buf; + case LH: + // TODO: Check offset range. + W_LH(rd, ofs, rs); + return code->buf; + case LW: + if (ofs >= 0 && ofs < (1 << 7) && (ofs & 3) == 0 && is_rvc_reg(rd) && is_rvc_reg(rs)) { + C_LW(rd, ofs, rs); + return code->buf; + } + // TODO: Check offset range. + W_LW(rd, ofs, rs); + return code->buf; + case LD: + if (ofs >= 0 && ofs < (1 << 9) && (ofs & 7) == 0 && rs == SP) { + C_LDSP(rd, ofs); + return code->buf; + } + if (ofs >= 0 && ofs < (1 << 8) && (ofs & 7) == 0 && is_rvc_reg(rd) && is_rvc_reg(rs)) { + C_LD(rd, ofs, rs); + return code->buf; + } + // TODO: Check offset range. + W_LD(rd, ofs, rs); + return code->buf; + case LBU: + // TODO: Check offset range. + W_LBU(rd, ofs, rs); + return code->buf; + case LHU: + // TODO: Check offset range. + W_LHU(rd, ofs, rs); return code->buf; + case LWU: + // TODO: Check offset range. + W_LWU(rd, ofs, rs); + return code->buf; + default: break; } } return NULL; } static unsigned char *asm_sd(Inst *inst, Code *code) { - int rd = inst->opr1.reg.no; Expr *offset = inst->opr2.indirect.offset; if (offset == NULL || offset->kind == EX_FIXNUM) { - int64_t imm = offset != NULL ? offset->fixnum : 0; - int base_reg = inst->opr2.indirect.reg.no; - if (imm >= 0 && imm < (1 << 9) && (imm & 7) == 0 && base_reg == SP) { - C_SDSP(rd, imm); + int64_t ofs = offset != NULL ? offset->fixnum : 0; + int rs2 = inst->opr1.reg.no; + int rs1 = inst->opr2.indirect.reg.no; + switch (inst->op) { + case SB: + // TODO: Check offset range. + W_SB(rs2, ofs, rs1); + return code->buf; + case SH: + // TODO: Check offset range. + W_SH(rs2, ofs, rs1); + return code->buf; + case SW: + if (ofs >= 0 && ofs < (1 << 7) && (ofs & 3) == 0 && is_rvc_reg(rs1) && is_rvc_reg(rs2)) { + C_SW(rs2, ofs, rs1); + return code->buf; + } + // TODO: Check offset range. + W_SW(rs2, ofs, rs1); return code->buf; + case SD: + if (ofs >= 0 && ofs < (1 << 9) && (ofs & 7) == 0 && rs1 == SP) { + C_SDSP(rs2, ofs); + return code->buf; + } + if (ofs >= 0 && ofs < (1 << 8) && (ofs & 7) == 0 && is_rvc_reg(rs1) && is_rvc_reg(rs2)) { + C_SD(rs2, ofs, rs1); + return code->buf; + } + // TODO: Check offset range. + W_SD(rs2, ofs, rs1); + return code->buf; + default: break; } } return NULL; @@ -155,13 +238,13 @@ static unsigned char *asm_sd(Inst *inst, Code *code) { static unsigned char *asm_call_d(Inst *inst, Code *code) { UNUSED(inst); - AUIPC(RA, 0); - JALR(RA, RA, 0); + W_AUIPC(RA, 0); + W_JALR(RA, RA, 0); return code->buf; } static unsigned char *asm_ret(Inst *inst, Code *code) { - RET(); + P_RET(); return code->buf; } @@ -176,13 +259,22 @@ typedef struct { int flag; } AsmInstTable; +static const AsmInstTable table_ld[] ={ + {asm_ld, REG, INDIRECT, NOOPERAND}, + {NULL} }; + +static const AsmInstTable table_sd[] ={ + {asm_sd, REG, INDIRECT, NOOPERAND}, + {NULL} }; + static const AsmInstTable *table[] = { [NOOP] = (const AsmInstTable[]){ {asm_noop, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, [LI] = (const AsmInstTable[]){ {asm_li, REG, IMMEDIATE, NOOPERAND}, {NULL} }, [LA] = (const AsmInstTable[]){ {asm_la, REG, DIRECT, DIRECT}, {NULL} }, [ADDI] = (const AsmInstTable[]){ {asm_addi, REG, REG, IMMEDIATE}, {NULL} }, - [LD] = (const AsmInstTable[]){ {asm_ld, REG, INDIRECT, NOOPERAND}, {NULL} }, - [SD] = (const AsmInstTable[]){ {asm_sd, REG, INDIRECT, NOOPERAND}, {NULL} }, + [LB] = table_ld, [LH] = table_ld, [LW] = table_ld, [LD] = table_ld, + [LBU] = table_ld, [LHU] = table_ld, [LWU] = table_ld, + [SB] = table_sd, [SH] = table_sd, [SW] = table_sd, [SD] = table_sd, [CALL] = (const AsmInstTable[]){ {asm_call_d, DIRECT, NOOPERAND, NOOPERAND}, {NULL} }, [RET] = (const AsmInstTable[]){ {asm_ret, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, }; diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 94f2ec024..7d79a62d4 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -12,8 +12,9 @@ enum Opcode { LI, LA, ADDI, - LD, - SD, + LB, LH, LW, LD, + LBU, LHU, LWU, + SB, SH, SW, SD, CALL, RET, }; diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 52065101e..6ecef973d 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -14,8 +14,9 @@ static const char *kOpTable[] = { "li", "la", "addi", - "ld", - "sd", + "lb", "lh", "lw", "ld", + "lbu", "lhu", "lwu", + "sb", "sh", "sw", "sd", "call", "ret", }; From 0ee4729b6f9ded6510e075fd353a1456653c5f66 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Fri, 19 Apr 2024 08:42:03 +0900 Subject: [PATCH 05/25] Run fibonacci example * Conditional branch / Jump * `add` * `mv` --- include/elf.h | 4 + src/as/arch/riscv64/asm_code.c | 134 ++++++++++++++++++++++++---- src/as/arch/riscv64/inst.h | 9 +- src/as/arch/riscv64/ir_asm.c | 37 ++++++++ src/as/arch/riscv64/parse_riscv64.c | 6 +- src/as/as.c | 34 +++++-- src/as/ir_asm.h | 5 +- 7 files changed, 205 insertions(+), 24 deletions(-) diff --git a/include/elf.h b/include/elf.h index 0b0913755..4e629beba 100644 --- a/include/elf.h +++ b/include/elf.h @@ -147,9 +147,13 @@ typedef struct { #define R_X86_64_PC32 (2) /* PC relative 32 bit signed */ #define R_X86_64_PLT32 (4) /* 32 bit PLT address */ +#define R_RISCV_BRANCH (16) +#define R_RISCV_JAL (17) #define R_RISCV_CALL (18) #define R_RISCV_PCREL_HI20 (23) #define R_RISCV_PCREL_LO12_I (24) +#define R_RISCV_RVC_BRANCH (44) +#define R_RISCV_RVC_JUMP (45) #define R_RISCV_RELAX (51) #define ELF64_R_SYM(info) ((info) >> 32) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index b5cd1b10d..d110271b7 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -61,6 +61,8 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define UTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 31, 12) << 12) | ((rd) << 7) | (opcode)) // U-type #define JTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 20, 20) << 31) | (IMM(imm, 10, 1) << 20) | (IMM(imm, 11, 11) << 19) | (IMM(imm, 19, 12) << 12) | ((rd) << 7) | (opcode)) // J-type +#define W_ADD(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x00, rd, 0x33) +#define W_ADDW(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x00, rd, 0x3b) #define W_ADDI(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x13) #define W_ADDIW(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x1b) #define W_LB(rd, ofs, rs) ITYPE(ofs, rs, 0x00, rd, 0x03) @@ -76,9 +78,13 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_SD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x23) #define W_AUIPC(rd, imm) UTYPE(imm, rd, 0x17) #define W_JALR(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x67) +#define W_BXX(funct3, rs1, rs2, ofs) STYPE(ofs, rs2, rs1, funct3, 0x63) +#define C_MV(rd, rs) MAKE_CODE16(inst, code, 0x8002 | ((rd) << 7) | ((rs) << 2)) #define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) #define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_ADD(rd, rs) MAKE_CODE16(inst, code, 0x9002 | ((rd) << 7) | ((rs) << 2)) +#define C_ADDW(rd, rs) MAKE_CODE16(inst, code, 0x9c21 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) #define C_ADDI(rd, imm) MAKE_CODE16(inst, code, 0x0001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) #define C_ADDIW(rd, imm) MAKE_CODE16(inst, code, 0x2001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) #define C_LW(rd, imm, rs) MAKE_CODE16(inst, code, 0x4000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 2, 2) << 6) | (IMM(imm, 6, 6) << 5) | (to_rvc_reg(rd) << 2)) @@ -87,13 +93,67 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define C_SD(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xe000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rs2) << 2)) #define C_LDSP(rd, imm) MAKE_CODE16(inst, code, 0x6002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) #define C_SDSP(rs, imm) MAKE_CODE16(inst, code, 0xe002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) +#define C_J() MAKE_CODE16(inst, code, 0xa001) #define C_JR(rs) MAKE_CODE16(inst, code, 0x8002 | ((rs) << 7)) +#define C_BEQZ(rs) MAKE_CODE16(inst, code, 0xc001 | (to_rvc_reg(rs) << 7)) +#define C_BNEZ(rs) MAKE_CODE16(inst, code, 0xe001 | (to_rvc_reg(rs) << 7)) #define P_RET() C_JR(RA) #define P_LI(rd, imm) W_ADDI(rd, ZERO, imm) -extern inline bool is_rvc_reg(int reg) { return reg >= 8 && reg <= 15; } // X8~X15 -extern inline int to_rvc_reg(int reg) { return reg - 8; } +extern inline bool is_rvc_reg(int reg); +extern inline int to_rvc_reg(int reg); + +static unsigned char *asm_3r(Inst *inst, Code *code) { + assert(inst->opr1.type == REG); + assert(inst->opr2.type == REG); + assert(inst->opr3.type == REG); + int rd = inst->opr1.reg.no; + int rs1 = inst->opr2.reg.no; + int rs2 = inst->opr3.reg.no; + if (rd == rs1) { + if (inst->op == ADD) { + C_ADD(rd, rs2); + return code->buf; + } + + if (is_rvc_reg(rd) && is_rvc_reg(rs2)) { + switch (inst->op) { + case ADDW: C_ADDW(rd, rs2); return code->buf; + default: break; + } + } + } + + switch (inst->op) { + case ADD: W_ADD(rd, rs1, rs2); break; + case ADDW: W_ADDW(rd, rs1, rs2); break; + default: assert(false); return NULL; + } + return code->buf; +} + +static unsigned char *asm_2ri(Inst *inst, Code *code) { + assert(inst->opr1.type == REG); + assert(inst->opr2.type == REG); + assert(inst->opr3.type == IMMEDIATE); + int rd = inst->opr1.reg.no; + int rs = inst->opr2.reg.no; + int64_t imm =inst->opr3.immediate; + if (rd == rs && is_im6(imm)) { + switch (inst->op) { + case ADDI: if (imm != 0) { C_ADDI(rd, imm); return code->buf; } break; + case ADDIW: C_ADDIW(rd, imm); return code->buf; + default: break; + } + } + switch (inst->op) { + case ADDI: W_ADDI(rd, rs, imm); break; + case ADDIW: W_ADDIW(rd, rs, imm); break; + default: assert(false); return NULL; + } + return code->buf; +} static unsigned char *asm_noop(Inst *inst, Code *code) { UNUSED(inst); @@ -101,6 +161,13 @@ static unsigned char *asm_noop(Inst *inst, Code *code) { return p; } +static unsigned char *asm_mv(Inst *inst, Code *code) { + int rd = inst->opr1.reg.no; + int rs = inst->opr2.reg.no; + C_MV(rd, rs); + return code->buf; +} + static unsigned char *asm_li(Inst *inst, Code *code) { int rd = inst->opr1.reg.no; int64_t imm =inst->opr2.immediate; @@ -129,19 +196,6 @@ static unsigned char *asm_la(Inst *inst, Code *code) { return code->buf; } -static unsigned char *asm_addi(Inst *inst, Code *code) { - int rd = inst->opr1.reg.no; - int rs = inst->opr2.reg.no; - int64_t imm =inst->opr3.immediate; - if (rd == rs && is_im6(imm) && imm != 0) { - C_ADDI(rd, imm); - } else { - // TODO: - return NULL; - } - return code->buf; -} - static unsigned char *asm_ld(Inst *inst, Code *code) { int rd = inst->opr1.reg.no; Expr *offset = inst->opr2.indirect.offset; @@ -236,6 +290,37 @@ static unsigned char *asm_sd(Inst *inst, Code *code) { return NULL; } +static unsigned char *asm_j(Inst *inst, Code *code) { + UNUSED(inst); + // TODO: Non compact instruction? + // imm[11|4|9:8|10|6|7|3:1|5] + C_J(); + return code->buf; +} + +#define _BEQ 0x0 +#define _BNE 0x1 +#define _BLT 0x4 +#define _BGE 0x5 +#define _BLTU 0x6 +#define _BGEU 0x7 + +static unsigned char *asm_bxx(Inst *inst, Code *code) { + int rs1 = inst->opr1.reg.no; + int rs2 = inst->opr2.reg.no; + if (rs2 == ZERO && is_rvc_reg(rs1)) { + switch (inst->op) { + case BEQ: C_BEQZ(rs1); return code->buf; + case BNE: C_BNEZ(rs1); return code->buf; + default: break; + } + } + static const int kFunct3Table[] = { _BEQ, _BNE, _BLT, _BGE, _BLTU, _BGEU }; + int funct3 = kFunct3Table[inst->op - BEQ]; + W_BXX(funct3, rs1, rs2, 0); + return code->buf; +} + static unsigned char *asm_call_d(Inst *inst, Code *code) { UNUSED(inst); W_AUIPC(RA, 0); @@ -259,6 +344,14 @@ typedef struct { int flag; } AsmInstTable; +static const AsmInstTable table_3r[] ={ + {asm_3r, REG, REG, REG}, + {NULL} }; + +static const AsmInstTable table_2ri[] ={ + {asm_2ri, REG, REG, IMMEDIATE}, + {NULL} }; + static const AsmInstTable table_ld[] ={ {asm_ld, REG, INDIRECT, NOOPERAND}, {NULL} }; @@ -267,14 +360,23 @@ static const AsmInstTable table_sd[] ={ {asm_sd, REG, INDIRECT, NOOPERAND}, {NULL} }; +static const AsmInstTable table_bxx[] ={ + {asm_bxx, REG, REG, DIRECT}, + {NULL} }; + static const AsmInstTable *table[] = { [NOOP] = (const AsmInstTable[]){ {asm_noop, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, + [MV] = (const AsmInstTable[]){ {asm_mv, REG, REG, NOOPERAND}, {NULL} }, [LI] = (const AsmInstTable[]){ {asm_li, REG, IMMEDIATE, NOOPERAND}, {NULL} }, [LA] = (const AsmInstTable[]){ {asm_la, REG, DIRECT, DIRECT}, {NULL} }, - [ADDI] = (const AsmInstTable[]){ {asm_addi, REG, REG, IMMEDIATE}, {NULL} }, + [ADD] = table_3r, [ADDW] = table_3r, + [ADDI] = table_2ri, [ADDIW] = table_2ri, [LB] = table_ld, [LH] = table_ld, [LW] = table_ld, [LD] = table_ld, [LBU] = table_ld, [LHU] = table_ld, [LWU] = table_ld, [SB] = table_sd, [SH] = table_sd, [SW] = table_sd, [SD] = table_sd, + [J] = (const AsmInstTable[]){ {asm_j, DIRECT, NOOPERAND, NOOPERAND}, {NULL} }, + [BEQ] = table_bxx, [BNE] = table_bxx, [BLT] = table_bxx, [BGE] = table_bxx, + [BLTU] = table_bxx, [BGEU] = table_bxx, [CALL] = (const AsmInstTable[]){ {asm_call_d, DIRECT, NOOPERAND, NOOPERAND}, {NULL} }, [RET] = (const AsmInstTable[]){ {asm_ret, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, }; diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 7d79a62d4..24b9c2cec 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -9,12 +9,16 @@ typedef struct Expr Expr; // Must match the order with kOpTable in parse_riscv64.c enum Opcode { NOOP, + MV, LI, LA, - ADDI, + ADD, ADDW, + ADDI, ADDIW, LB, LH, LW, LD, LBU, LHU, LWU, SB, SH, SW, SD, + J, + BEQ, BNE, BLT, BGE, BLTU, BGEU, CALL, RET, }; @@ -59,3 +63,6 @@ typedef struct Inst { Operand opr2; Operand opr3; } Inst; + +inline bool is_rvc_reg(int reg) { return reg >= 8 && reg <= 15; } // X8~X15 +inline int to_rvc_reg(int reg) { return reg - 8; } diff --git a/src/as/arch/riscv64/ir_asm.c b/src/as/arch/riscv64/ir_asm.c index 3dcfe295f..68572a425 100644 --- a/src/as/arch/riscv64/ir_asm.c +++ b/src/as/arch/riscv64/ir_asm.c @@ -213,6 +213,43 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * } } break; + case J: + if (inst->opr1.type == DIRECT) { + Value value = calc_expr(label_table, inst->opr1.direct.expr); + if (value.label != NULL) { + // Put rela even if the label is defined in the same object file. + UnresolvedInfo *info; + info = calloc_or_die(sizeof(*info)); + info->kind = UNRES_RISCV_RVC_JUMP; + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset; + vec_push(unresolved, info); + break; + } + } + break; + case BEQ: case BNE: case BLT: case BGE: case BLTU: case BGEU: + if (inst->opr3.type == DIRECT) { + Value value = calc_expr(label_table, inst->opr3.direct.expr); + if (value.label != NULL) { + assert(inst->opr2.type == REG); + bool comp = inst->opr2.reg.no == 0 && is_rvc_reg(inst->opr1.reg.no) && + (inst->op == BEQ || inst->op == BNE); + // Put rela even if the label is defined in the same object file. + UnresolvedInfo *info; + info = calloc_or_die(sizeof(*info)); + info->kind = comp ? UNRES_RISCV_RVC_BRANCH : UNRES_RISCV_BRANCH; + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset; + vec_push(unresolved, info); + break; + } + } + break; case CALL: if (inst->opr1.type == DIRECT) { Value value = calc_expr(label_table, inst->opr1.direct.expr); diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 6ecef973d..135f79507 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -11,12 +11,16 @@ // Align with Opcode. static const char *kOpTable[] = { + "mv", "li", "la", - "addi", + "add", "addw", + "addi", "addiw", "lb", "lh", "lw", "ld", "lbu", "lhu", "lwu", "sb", "sh", "sw", "sd", + "j", + "beq", "bne", "blt", "bge", "bltu", "bgeu", "call", "ret", }; diff --git a/src/as/as.c b/src/as/as.c index 8c2f6cae9..be40a4896 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -251,6 +251,20 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { rela->r_addend = u->add + (label->address - section_start_addresses[label->section]); } } + break; + case UNRES_RISCV_BRANCH: + case UNRES_RISCV_RVC_BRANCH: + { + Elf64_Sym *sym = symtab_add(&symtab, u->label); + size_t index = sym - symtab.buf; + + rela->r_offset = u->offset; + rela->r_info = ELF64_R_INFO(index, u->kind == UNRES_RISCV_RVC_BRANCH ? R_RISCV_RVC_BRANCH + : R_RISCV_BRANCH); + rela->r_addend = u->add; + } + break; + break; case UNRES_RISCV_CALL: { @@ -262,21 +276,31 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { rela->r_addend = u->add; } break; - case UNRES_RISCV_RELAX: + case UNRES_RISCV_PCREL_HI20: + case UNRES_RISCV_PCREL_LO12_I: { + int symidx = symtab_find(&symtab, u->label); + assert(symidx >= 0); + rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(0, R_RISCV_RELAX); + rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_RISCV_PCREL_HI20 ? R_RISCV_PCREL_HI20 : R_RISCV_PCREL_LO12_I); rela->r_addend = u->add; } break; - case UNRES_RISCV_PCREL_HI20: - case UNRES_RISCV_PCREL_LO12_I: + case UNRES_RISCV_RVC_JUMP: { int symidx = symtab_find(&symtab, u->label); assert(symidx >= 0); rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_RISCV_PCREL_HI20 ? R_RISCV_PCREL_HI20 : R_RISCV_PCREL_LO12_I); + rela->r_info = ELF64_R_INFO(symidx, R_RISCV_RVC_JUMP); + rela->r_addend = u->add; + } + break; + case UNRES_RISCV_RELAX: + { + rela->r_offset = u->offset; + rela->r_info = ELF64_R_INFO(0, R_RISCV_RELAX); rela->r_addend = u->add; } break; diff --git a/src/as/ir_asm.h b/src/as/ir_asm.h index 11301ebd1..ad252ac11 100644 --- a/src/as/ir_asm.h +++ b/src/as/ir_asm.h @@ -37,10 +37,13 @@ enum UnresolvedKind { UNRES_OTHER_SECTION, UNRES_ABS64, + UNRES_RISCV_BRANCH, UNRES_RISCV_CALL, - UNRES_RISCV_RELAX, UNRES_RISCV_PCREL_HI20, UNRES_RISCV_PCREL_LO12_I, + UNRES_RISCV_RVC_BRANCH, + UNRES_RISCV_RVC_JUMP, + UNRES_RISCV_RELAX, }; typedef struct { From 108a9a2067a69fe0eaa2a4fc8bfc97ba5615035f Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 20 Apr 2024 08:58:48 +0900 Subject: [PATCH 06/25] Arithmetic instructions --- src/as/arch/riscv64/asm_code.c | 50 ++++++++++++++++++++++++++--- src/as/arch/riscv64/inst.h | 4 +++ src/as/arch/riscv64/parse_riscv64.c | 4 +++ 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index d110271b7..70d33211f 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -65,6 +65,18 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_ADDW(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x00, rd, 0x3b) #define W_ADDI(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x13) #define W_ADDIW(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x1b) +#define W_SUB(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x00, rd, 0x33) +#define W_SUBW(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x00, rd, 0x3b) +#define W_MUL(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x00, rd, 0x33) +#define W_MULW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x00, rd, 0x3b) +#define W_DIV(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x04, rd, 0x33) +#define W_DIVU(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x05, rd, 0x33) +#define W_DIVW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x04, rd, 0x3b) +#define W_DIVUW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x05, rd, 0x3b) +#define W_REM(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x06, rd, 0x33) +#define W_REMU(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x33) +#define W_REMW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x06, rd, 0x3b) +#define W_REMUW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x3b) #define W_LB(rd, ofs, rs) ITYPE(ofs, rs, 0x00, rd, 0x03) #define W_LH(rd, ofs, rs) ITYPE(ofs, rs, 0x01, rd, 0x03) #define W_LW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x03) @@ -87,6 +99,9 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define C_ADDW(rd, rs) MAKE_CODE16(inst, code, 0x9c21 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) #define C_ADDI(rd, imm) MAKE_CODE16(inst, code, 0x0001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) #define C_ADDIW(rd, imm) MAKE_CODE16(inst, code, 0x2001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_ADDI16SP(imm) MAKE_CODE16(inst, code, 0x6101 | (IMM(imm, 9, 9) << 12) | (IMM(imm, 4, 4) << 6) | (IMM(imm, 6, 6) << 5) | (IMM(imm, 8, 7) << 3) | (IMM(imm, 5, 5) << 2)) +#define C_SUB(rd, rs) MAKE_CODE16(inst, code, 0x8c01 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_SUBW(rd, rs) MAKE_CODE16(inst, code, 0x9c01 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) #define C_LW(rd, imm, rs) MAKE_CODE16(inst, code, 0x4000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 2, 2) << 6) | (IMM(imm, 6, 6) << 5) | (to_rvc_reg(rd) << 2)) #define C_LD(rd, imm, rs) MAKE_CODE16(inst, code, 0x6000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rd) << 2)) #define C_SW(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xc000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rs2) << 2)) @@ -120,6 +135,8 @@ static unsigned char *asm_3r(Inst *inst, Code *code) { if (is_rvc_reg(rd) && is_rvc_reg(rs2)) { switch (inst->op) { case ADDW: C_ADDW(rd, rs2); return code->buf; + case SUB: C_SUB(rd, rs2); return code->buf; + case SUBW: C_SUBW(rd, rs2); return code->buf; default: break; } } @@ -128,6 +145,18 @@ static unsigned char *asm_3r(Inst *inst, Code *code) { switch (inst->op) { case ADD: W_ADD(rd, rs1, rs2); break; case ADDW: W_ADDW(rd, rs1, rs2); break; + case SUB: W_SUB(rd, rs1, rs2); break; + case SUBW: W_SUBW(rd, rs1, rs2); break; + case MUL: W_MUL(rd, rs1, rs2); break; + case MULW: W_MULW(rd, rs1, rs2); break; + case DIV: W_DIV(rd, rs1, rs2); break; + case DIVW: W_DIVW(rd, rs1, rs2); break; + case DIVU: W_DIVU(rd, rs1, rs2); break; + case DIVUW: W_DIVUW(rd, rs1, rs2); break; + case REM: W_REM(rd, rs1, rs2); break; + case REMW: W_REMW(rd, rs1, rs2); break; + case REMU: W_REMU(rd, rs1, rs2); break; + case REMUW: W_REMUW(rd, rs1, rs2); break; default: assert(false); return NULL; } return code->buf; @@ -140,11 +169,18 @@ static unsigned char *asm_2ri(Inst *inst, Code *code) { int rd = inst->opr1.reg.no; int rs = inst->opr2.reg.no; int64_t imm =inst->opr3.immediate; - if (rd == rs && is_im6(imm)) { - switch (inst->op) { - case ADDI: if (imm != 0) { C_ADDI(rd, imm); return code->buf; } break; - case ADDIW: C_ADDIW(rd, imm); return code->buf; - default: break; + if (rd == rs) { + if (is_im6(imm)) { + switch (inst->op) { + case ADDI: if (imm != 0) { C_ADDI(rd, imm); return code->buf; } break; + case ADDIW: C_ADDIW(rd, imm); return code->buf; + default: break; + } + } + + if (rd == SP && is_im6(imm >> 4) && (imm & 0xf) == 0 && imm != 0) { + C_ADDI16SP(imm); + return code->buf; } } switch (inst->op) { @@ -371,6 +407,10 @@ static const AsmInstTable *table[] = { [LA] = (const AsmInstTable[]){ {asm_la, REG, DIRECT, DIRECT}, {NULL} }, [ADD] = table_3r, [ADDW] = table_3r, [ADDI] = table_2ri, [ADDIW] = table_2ri, + [SUB] = table_3r, [SUBW] = table_3r, + [MUL] = table_3r, [MULW] = table_3r, + [DIV] = table_3r, [DIVU] = table_3r, [DIVW] = table_3r, [DIVUW] = table_3r, + [REM] = table_3r, [REMU] = table_3r, [REMW] = table_3r, [REMUW] = table_3r, [LB] = table_ld, [LH] = table_ld, [LW] = table_ld, [LD] = table_ld, [LBU] = table_ld, [LHU] = table_ld, [LWU] = table_ld, [SB] = table_sd, [SH] = table_sd, [SW] = table_sd, [SD] = table_sd, diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 24b9c2cec..9b234d6ef 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -14,6 +14,10 @@ enum Opcode { LA, ADD, ADDW, ADDI, ADDIW, + SUB, SUBW, + MUL, MULW, + DIV, DIVU, DIVW, DIVUW, + REM, REMU, REMW, REMUW, LB, LH, LW, LD, LBU, LHU, LWU, SB, SH, SW, SD, diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 135f79507..cb7700019 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -16,6 +16,10 @@ static const char *kOpTable[] = { "la", "add", "addw", "addi", "addiw", + "sub", "subw", + "mul", "mulw", + "div", "divu", "divw", "divuw", + "rem", "remu", "remw", "remuw", "lb", "lh", "lw", "ld", "lbu", "lhu", "lwu", "sb", "sh", "sw", "sd", From a550712974ac4047a2009d0ecd087f9296d50706 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 20 Apr 2024 11:48:04 +0900 Subject: [PATCH 07/25] Handle 32bit immediate value --- src/as/arch/riscv64/asm_code.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 70d33211f..c3f5c7030 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -38,10 +38,6 @@ inline bool is_im12(int64_t x) { return x <= ((1L << 11) - 1) && x >= -(1L << 11); } -inline bool is_im18(int64_t x) { - return x <= ((1L << 17) - 1) && x >= -(1L << 17); -} - inline bool assemble_error(const ParseInfo *info, const char *message) { parse_error(info, message); return false; @@ -211,10 +207,14 @@ static unsigned char *asm_li(Inst *inst, Code *code) { C_LI(rd, imm); } else if (is_im12(imm)) { P_LI(rd, imm); - } else if (is_im18(imm)) { + } else if (is_im32(imm)) { int h = imm >> 12, l = imm & 0xfff; + if (l >= 0x800) { + l = l - 0x1000; + h += 1; + } C_LUI(rd, h); - if (is_im6(imm)) + if (is_im6(l)) C_ADDIW(rd, l); else W_ADDIW(rd, rd, l); From e9db1b7f2cac08085bf52626fa4900e6c22b3f99 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sat, 20 Apr 2024 15:13:26 +0900 Subject: [PATCH 08/25] Bit and shift instructions --- src/as/arch/riscv64/asm_code.c | 59 +++++++++++++++++++++++++++++ src/as/arch/riscv64/inst.h | 6 +++ src/as/arch/riscv64/parse_riscv64.c | 6 +++ 3 files changed, 71 insertions(+) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index c3f5c7030..32db051a1 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -73,6 +73,19 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_REMU(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x33) #define W_REMW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x06, rd, 0x3b) #define W_REMUW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x3b) +#define W_AND(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x07, rd, 0x33) +#define W_ANDI(rd, rs, imm) ITYPE(imm, rs, 0x07, rd, 0x13) +#define W_OR(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x06, rd, 0x33) +#define W_ORI(rd, rs, imm) ITYPE(imm, rs, 0x06, rd, 0x13) +#define W_XOR(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x04, rd, 0x33) +#define W_XORI(rd, rs, imm) ITYPE(imm, rs, 0x04, rd, 0x13) +#define W_SLL(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x01, rd, 0x33) +#define W_SLLI(rd, rs, imm) ITYPE((imm) & 63, rs, 0x01, rd, 0x13) +#define W_SLLIW(rd, rs, imm) ITYPE((imm) & 31, rs, 0x01, rd, 0x1b) +#define W_SRL(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x05, rd, 0x33) +#define W_SRLI(rd, rs, imm) ITYPE((imm) & 63, rs, 0x05, rd, 0x13) +#define W_SRA(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x05, rd, 0x33) +#define W_SRAI(rd, rs, imm) ITYPE(0x400 | ((imm) & 63), rs, 0x05, rd, 0x13) #define W_LB(rd, ofs, rs) ITYPE(ofs, rs, 0x00, rd, 0x03) #define W_LH(rd, ofs, rs) ITYPE(ofs, rs, 0x01, rd, 0x03) #define W_LW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x03) @@ -98,6 +111,13 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define C_ADDI16SP(imm) MAKE_CODE16(inst, code, 0x6101 | (IMM(imm, 9, 9) << 12) | (IMM(imm, 4, 4) << 6) | (IMM(imm, 6, 6) << 5) | (IMM(imm, 8, 7) << 3) | (IMM(imm, 5, 5) << 2)) #define C_SUB(rd, rs) MAKE_CODE16(inst, code, 0x8c01 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) #define C_SUBW(rd, rs) MAKE_CODE16(inst, code, 0x9c01 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_AND(rd, rs) MAKE_CODE16(inst, code, 0x8c61 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_ANDI(rd, imm) MAKE_CODE16(inst, code, 0x8801 | (IMM(imm, 5, 5) << 12) | (to_rvc_reg(rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_OR(rd, rs) MAKE_CODE16(inst, code, 0x8c41 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_XOR(rd, rs) MAKE_CODE16(inst, code, 0x8c21 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_SLLI(rd, imm) MAKE_CODE16(inst, code, 0x0002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_SRLI(rd, imm) MAKE_CODE16(inst, code, 0x8001 | (IMM(imm, 5, 5) << 12) | (to_rvc_reg(rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_SRAI(rd, imm) MAKE_CODE16(inst, code, 0x8401 | (IMM(imm, 5, 5) << 12) | (to_rvc_reg(rd) << 7) | (IMM(imm, 4, 0) << 2)) #define C_LW(rd, imm, rs) MAKE_CODE16(inst, code, 0x4000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 2, 2) << 6) | (IMM(imm, 6, 6) << 5) | (to_rvc_reg(rd) << 2)) #define C_LD(rd, imm, rs) MAKE_CODE16(inst, code, 0x6000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rd) << 2)) #define C_SW(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xc000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rs2) << 2)) @@ -133,6 +153,9 @@ static unsigned char *asm_3r(Inst *inst, Code *code) { case ADDW: C_ADDW(rd, rs2); return code->buf; case SUB: C_SUB(rd, rs2); return code->buf; case SUBW: C_SUBW(rd, rs2); return code->buf; + case AND: C_AND(rd, rs2); return code->buf; + case OR: C_OR(rd, rs2); return code->buf; + case XOR: C_XOR(rd, rs2); return code->buf; default: break; } } @@ -153,6 +176,12 @@ static unsigned char *asm_3r(Inst *inst, Code *code) { case REMW: W_REMW(rd, rs1, rs2); break; case REMU: W_REMU(rd, rs1, rs2); break; case REMUW: W_REMUW(rd, rs1, rs2); break; + case AND: W_AND(rd, rs1, rs2); break; + case OR: W_OR(rd, rs1, rs2); break; + case XOR: W_XOR(rd, rs1, rs2); break; + case SLL: W_SLL(rd, rs1, rs2); break; + case SRL: W_SRL(rd, rs1, rs2); break; + case SRA: W_SRA(rd, rs1, rs2); break; default: assert(false); return NULL; } return code->buf; @@ -170,6 +199,23 @@ static unsigned char *asm_2ri(Inst *inst, Code *code) { switch (inst->op) { case ADDI: if (imm != 0) { C_ADDI(rd, imm); return code->buf; } break; case ADDIW: C_ADDIW(rd, imm); return code->buf; + case ANDI: if (is_rvc_reg(rd)) { C_ANDI(rd, imm); return code->buf; } break; + case SLLI: + if (rd != 0 && imm != 0) { + C_SLLI(rd, imm); + return code->buf; + } + break; + case SRLI: + if (is_rvc_reg(rd)) { + C_SRLI(rd, imm); return code->buf; + } + break; + case SRAI: + if (is_rvc_reg(rd)) { + C_SRAI(rd, imm); return code->buf; + } + break; default: break; } } @@ -182,6 +228,13 @@ static unsigned char *asm_2ri(Inst *inst, Code *code) { switch (inst->op) { case ADDI: W_ADDI(rd, rs, imm); break; case ADDIW: W_ADDIW(rd, rs, imm); break; + case ANDI: W_ANDI(rd, rs, imm); break; + case ORI: W_ORI(rd, rs, imm); break; + case XORI: W_XORI(rd, rs, imm); break; + case SLLI: W_SLLI(rd, rs, imm); break; + case SLLIW: W_SLLIW(rd, rs, imm); break; + case SRLI: W_SRLI(rd, rs, imm); break; + case SRAI: W_SRAI(rd, rs, imm); break; default: assert(false); return NULL; } return code->buf; @@ -411,6 +464,12 @@ static const AsmInstTable *table[] = { [MUL] = table_3r, [MULW] = table_3r, [DIV] = table_3r, [DIVU] = table_3r, [DIVW] = table_3r, [DIVUW] = table_3r, [REM] = table_3r, [REMU] = table_3r, [REMW] = table_3r, [REMUW] = table_3r, + [AND] = table_3r, [ANDI] = table_2ri, + [OR] = table_3r, [ORI] = table_2ri, + [XOR] = table_3r, [XORI] = table_2ri, + [SLL] = table_3r, [SLLI] = table_2ri, [SLLIW] = table_2ri, + [SRL] = table_3r, [SRLI] = table_2ri, [SRLIW] = table_2ri, + [SRA] = table_3r, [SRAI] = table_2ri, [LB] = table_ld, [LH] = table_ld, [LW] = table_ld, [LD] = table_ld, [LBU] = table_ld, [LHU] = table_ld, [LWU] = table_ld, [SB] = table_sd, [SH] = table_sd, [SW] = table_sd, [SD] = table_sd, diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 9b234d6ef..6526dde80 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -18,6 +18,12 @@ enum Opcode { MUL, MULW, DIV, DIVU, DIVW, DIVUW, REM, REMU, REMW, REMUW, + AND, ANDI, + OR, ORI, + XOR, XORI, + SLL, SLLI, SLLIW, + SRL, SRLI, SRLIW, + SRA, SRAI, LB, LH, LW, LD, LBU, LHU, LWU, SB, SH, SW, SD, diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index cb7700019..0a60b8834 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -20,6 +20,12 @@ static const char *kOpTable[] = { "mul", "mulw", "div", "divu", "divw", "divuw", "rem", "remu", "remw", "remuw", + "and", "andi", + "or", "ori", + "xor", "xori", + "sll", "slli", "slliw", + "srl", "srli", "srliw", + "sra", "srai", "lb", "lh", "lw", "ld", "lbu", "lhu", "lwu", "sb", "sh", "sw", "sd", From 8704119fa180303379e8df72cfd512d689f279ae Mon Sep 17 00:00:00 2001 From: tyfkda Date: Sun, 21 Apr 2024 14:21:44 +0900 Subject: [PATCH 09/25] Jump --- src/as/arch/riscv64/asm_code.c | 15 +++++++++++++++ src/as/arch/riscv64/inst.h | 2 ++ src/as/arch/riscv64/parse_riscv64.c | 2 ++ 3 files changed, 19 insertions(+) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 32db051a1..f69881615 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -126,6 +126,7 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define C_SDSP(rs, imm) MAKE_CODE16(inst, code, 0xe002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) #define C_J() MAKE_CODE16(inst, code, 0xa001) #define C_JR(rs) MAKE_CODE16(inst, code, 0x8002 | ((rs) << 7)) +#define C_JALR(rs) MAKE_CODE16(inst, code, 0x9002 | ((rs) << 7)) #define C_BEQZ(rs) MAKE_CODE16(inst, code, 0xc001 | (to_rvc_reg(rs) << 7)) #define C_BNEZ(rs) MAKE_CODE16(inst, code, 0xe001 | (to_rvc_reg(rs) << 7)) @@ -387,6 +388,18 @@ static unsigned char *asm_j(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_jr(Inst *inst, Code *code) { + int rs = inst->opr1.reg.no; + C_JR(rs); + return code->buf; +} + +static unsigned char *asm_jalr(Inst *inst, Code *code) { + int rs = inst->opr1.reg.no; + C_JALR(rs); + return code->buf; +} + #define _BEQ 0x0 #define _BNE 0x1 #define _BLT 0x4 @@ -474,6 +487,8 @@ static const AsmInstTable *table[] = { [LBU] = table_ld, [LHU] = table_ld, [LWU] = table_ld, [SB] = table_sd, [SH] = table_sd, [SW] = table_sd, [SD] = table_sd, [J] = (const AsmInstTable[]){ {asm_j, DIRECT, NOOPERAND, NOOPERAND}, {NULL} }, + [JR] = (const AsmInstTable[]){ {asm_jr, REG, NOOPERAND, NOOPERAND}, {NULL} }, + [JALR] = (const AsmInstTable[]){ {asm_jalr, REG, NOOPERAND, NOOPERAND}, {NULL} }, [BEQ] = table_bxx, [BNE] = table_bxx, [BLT] = table_bxx, [BGE] = table_bxx, [BLTU] = table_bxx, [BGEU] = table_bxx, [CALL] = (const AsmInstTable[]){ {asm_call_d, DIRECT, NOOPERAND, NOOPERAND}, {NULL} }, diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 6526dde80..78399a52c 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -28,6 +28,8 @@ enum Opcode { LBU, LHU, LWU, SB, SH, SW, SD, J, + JR, + JALR, BEQ, BNE, BLT, BGE, BLTU, BGEU, CALL, RET, diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 0a60b8834..b2212f703 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -30,6 +30,8 @@ static const char *kOpTable[] = { "lbu", "lhu", "lwu", "sb", "sh", "sw", "sd", "j", + "jr", + "jalr", "beq", "bne", "blt", "bge", "bltu", "bgeu", "call", "ret", From fc61c137f8f154817c4423d07cc6159f8f8129f1 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 22 Apr 2024 09:31:50 +0900 Subject: [PATCH 10/25] NEG, NOT, sext, zext --- src/as/arch/riscv64/asm_code.c | 35 +++++++++++++++++++++++++++++ src/as/arch/riscv64/inst.h | 4 ++++ src/as/arch/riscv64/parse_riscv64.c | 6 ++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index f69881615..09a301579 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -132,6 +132,14 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define P_RET() C_JR(RA) #define P_LI(rd, imm) W_ADDI(rd, ZERO, imm) +#define P_NEG(rd, rs) W_SUB(rd, ZERO, rs) +#define P_NOT(rd, rs) W_XORI(rd, rs, -1) +#define P_SEXT_B(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 56); else W_SLLI(rd, rs, 56); C_SRAI(rd, 56); } while (0) +#define P_SEXT_H(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 48); else W_SLLI(rd, rs, 48); C_SRAI(rd, 48); } while (0) +#define P_SEXT_W(rd, rs) do { if ((rd) == (rs)) C_ADDIW(rd, 0); else W_ADDIW(rd, rs, 0); } while (0) +#define P_ZEXT_B(rd, rs) W_ANDI(rd, rs, 0xff) +#define P_ZEXT_H(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 48); else W_SLLI(rd, rs, 48); C_SRLI(rd, 48); } while (0) +#define P_ZEXT_W(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 32); else W_SLLI(rd, rs, 32); C_SRLI(rd, 32); } while (0) extern inline bool is_rvc_reg(int reg); extern inline int to_rvc_reg(int reg); @@ -241,6 +249,25 @@ static unsigned char *asm_2ri(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_2r(Inst *inst, Code *code) { + assert(inst->opr1.type == REG); + assert(inst->opr2.type == REG); + int rd = inst->opr1.reg.no; + int rs = inst->opr2.reg.no; + switch (inst->op) { + case NEG: P_NEG(rd, rs); break; + case NOT: P_NOT(rd, rs); break; + case SEXT_B: P_SEXT_B(rd, rs); break; + case SEXT_H: P_SEXT_H(rd, rs); break; + case SEXT_W: P_SEXT_W(rd, rs); break; + case ZEXT_B: P_ZEXT_B(rd, rs); break; + case ZEXT_H: P_ZEXT_H(rd, rs); break; + case ZEXT_W: P_ZEXT_W(rd, rs); break; + default: assert(false); return NULL; + } + return code->buf; +} + static unsigned char *asm_noop(Inst *inst, Code *code) { UNUSED(inst); unsigned char *p = code->buf; @@ -454,6 +481,10 @@ static const AsmInstTable table_2ri[] ={ {asm_2ri, REG, REG, IMMEDIATE}, {NULL} }; +static const AsmInstTable table_2r[] ={ + {asm_2r, REG, REG, NOOPERAND}, + {NULL} }; + static const AsmInstTable table_ld[] ={ {asm_ld, REG, INDIRECT, NOOPERAND}, {NULL} }; @@ -480,6 +511,10 @@ static const AsmInstTable *table[] = { [AND] = table_3r, [ANDI] = table_2ri, [OR] = table_3r, [ORI] = table_2ri, [XOR] = table_3r, [XORI] = table_2ri, + [NEG] = table_2r, + [NOT] = table_2r, + [SEXT_B] = table_2r, [SEXT_H] = table_2r, [SEXT_W] = table_2r, + [ZEXT_B] = table_2r, [ZEXT_H] = table_2r, [ZEXT_W] = table_2r, [SLL] = table_3r, [SLLI] = table_2ri, [SLLIW] = table_2ri, [SRL] = table_3r, [SRLI] = table_2ri, [SRLIW] = table_2ri, [SRA] = table_3r, [SRAI] = table_2ri, diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 78399a52c..bcb591365 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -21,6 +21,10 @@ enum Opcode { AND, ANDI, OR, ORI, XOR, XORI, + NEG, + NOT, + SEXT_B, SEXT_H, SEXT_W, + ZEXT_B, ZEXT_H, ZEXT_W, SLL, SLLI, SLLIW, SRL, SRLI, SRLIW, SRA, SRAI, diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index b2212f703..790b0dbc5 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -23,6 +23,10 @@ static const char *kOpTable[] = { "and", "andi", "or", "ori", "xor", "xori", + "neg", + "not", + "sext.b", "sext.h", "sext.w", + "zext.b", "zext.h", "zext.w", "sll", "slli", "slliw", "srl", "srli", "srliw", "sra", "srai", @@ -146,7 +150,7 @@ static int find_match_index(const char **pp, const char **table, size_t count) { const char *p = *pp; const char *start = p; - while (isalnum(*p)) + while (isalnum(*p) || *p == '.') ++p; if (*p == '\0' || isspace(*p)) { size_t n = p - start; From ae839996b30c71bdddc3c6cabfe2f062fef17808 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 22 Apr 2024 10:05:07 +0900 Subject: [PATCH 11/25] SLT etc. --- src/as/arch/riscv64/asm_code.c | 18 ++++++++++++++++++ src/as/arch/riscv64/inst.h | 2 ++ src/as/arch/riscv64/parse_riscv64.c | 2 ++ 3 files changed, 22 insertions(+) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 09a301579..323b5f24f 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -86,6 +86,10 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_SRLI(rd, rs, imm) ITYPE((imm) & 63, rs, 0x05, rd, 0x13) #define W_SRA(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x05, rd, 0x33) #define W_SRAI(rd, rs, imm) ITYPE(0x400 | ((imm) & 63), rs, 0x05, rd, 0x13) +#define W_SLT(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x02, rd, 0x33) +#define W_SLTU(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x03, rd, 0x33) +#define W_SLTI(rd, rs, imm) ITYPE(imm, rs, 0x02, rd, 0x13) +#define W_SLTIU(rd, rs, imm) ITYPE(imm, rs, 0x03, rd, 0x13) #define W_LB(rd, ofs, rs) ITYPE(ofs, rs, 0x00, rd, 0x03) #define W_LH(rd, ofs, rs) ITYPE(ofs, rs, 0x01, rd, 0x03) #define W_LW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x03) @@ -140,6 +144,10 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define P_ZEXT_B(rd, rs) W_ANDI(rd, rs, 0xff) #define P_ZEXT_H(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 48); else W_SLLI(rd, rs, 48); C_SRLI(rd, 48); } while (0) #define P_ZEXT_W(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 32); else W_SLLI(rd, rs, 32); C_SRLI(rd, 32); } while (0) +#define P_SEQZ(rd, rs) W_SLTIU(rd, rs, 1) +#define P_SNEZ(rd, rs) W_SLTU(rd, ZERO, rs) +#define P_SLTZ(rd, rs) W_SLT(rd, rs, ZERO) +#define P_SGTZ(rd, rs) W_SLT(rd, ZERO, rs) extern inline bool is_rvc_reg(int reg); extern inline int to_rvc_reg(int reg); @@ -191,6 +199,8 @@ static unsigned char *asm_3r(Inst *inst, Code *code) { case SLL: W_SLL(rd, rs1, rs2); break; case SRL: W_SRL(rd, rs1, rs2); break; case SRA: W_SRA(rd, rs1, rs2); break; + case SLT: W_SLT(rd, rs1, rs2); break; + case SLTU: W_SLTU(rd, rs1, rs2); break; default: assert(false); return NULL; } return code->buf; @@ -244,6 +254,8 @@ static unsigned char *asm_2ri(Inst *inst, Code *code) { case SLLIW: W_SLLIW(rd, rs, imm); break; case SRLI: W_SRLI(rd, rs, imm); break; case SRAI: W_SRAI(rd, rs, imm); break; + case SLTI: W_SLTI(rd, rs, imm); break; + case SLTIU: W_SLTIU(rd, rs, imm); break; default: assert(false); return NULL; } return code->buf; @@ -263,6 +275,10 @@ static unsigned char *asm_2r(Inst *inst, Code *code) { case ZEXT_B: P_ZEXT_B(rd, rs); break; case ZEXT_H: P_ZEXT_H(rd, rs); break; case ZEXT_W: P_ZEXT_W(rd, rs); break; + case SEQZ: P_SEQZ(rd, rs); break; + case SNEZ: P_SNEZ(rd, rs); break; + case SLTZ: P_SLTZ(rd, rs); break; + case SGTZ: P_SGTZ(rd, rs); break; default: assert(false); return NULL; } return code->buf; @@ -521,6 +537,8 @@ static const AsmInstTable *table[] = { [LB] = table_ld, [LH] = table_ld, [LW] = table_ld, [LD] = table_ld, [LBU] = table_ld, [LHU] = table_ld, [LWU] = table_ld, [SB] = table_sd, [SH] = table_sd, [SW] = table_sd, [SD] = table_sd, + [SLT] = table_3r, [SLTI] = table_2ri, [SLTU] = table_3r, [SLTIU] = table_2ri, + [SEQZ] = table_2r, [SNEZ] = table_2r, [SLTZ] = table_2r, [SGTZ] = table_2r, [J] = (const AsmInstTable[]){ {asm_j, DIRECT, NOOPERAND, NOOPERAND}, {NULL} }, [JR] = (const AsmInstTable[]){ {asm_jr, REG, NOOPERAND, NOOPERAND}, {NULL} }, [JALR] = (const AsmInstTable[]){ {asm_jalr, REG, NOOPERAND, NOOPERAND}, {NULL} }, diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index bcb591365..dff842887 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -31,6 +31,8 @@ enum Opcode { LB, LH, LW, LD, LBU, LHU, LWU, SB, SH, SW, SD, + SLT, SLTU, SLTI, SLTIU, + SEQZ, SNEZ, SLTZ, SGTZ, J, JR, JALR, diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 790b0dbc5..6d089aed9 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -33,6 +33,8 @@ static const char *kOpTable[] = { "lb", "lh", "lw", "ld", "lbu", "lhu", "lwu", "sb", "sh", "sw", "sd", + "slt", "sltu", "slti", "sltiu", + "seqz", "snez", "sltz", "sgtz", "j", "jr", "jalr", From 73d2ad4fc3a9c477d311f81da3a9d29ecf9d4fb3 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 22 Apr 2024 14:34:58 +0900 Subject: [PATCH 12/25] Handle 64bit immediate Expanded up to 26 bytes. --- src/as/arch/riscv64/asm_code.c | 33 +++++++++++++++++++++++++-------- src/as/asm_code.h | 4 ++++ 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 323b5f24f..9ab81fc9c 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -101,13 +101,14 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_SH(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x01, 0x23) #define W_SW(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x02, 0x23) #define W_SD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x23) +#define W_LUI(rd, imm) UTYPE(imm, rd, 0x37) #define W_AUIPC(rd, imm) UTYPE(imm, rd, 0x17) #define W_JALR(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x67) #define W_BXX(funct3, rs1, rs2, ofs) STYPE(ofs, rs2, rs1, funct3, 0x63) #define C_MV(rd, rs) MAKE_CODE16(inst, code, 0x8002 | ((rd) << 7) | ((rs) << 2)) #define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 17, 17) << 12) | ((rd) << 7) | (IMM(imm, 16, 12) << 2)) #define C_ADD(rd, rs) MAKE_CODE16(inst, code, 0x9002 | ((rd) << 7) | ((rs) << 2)) #define C_ADDW(rd, rs) MAKE_CODE16(inst, code, 0x9c21 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) #define C_ADDI(rd, imm) MAKE_CODE16(inst, code, 0x0001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) @@ -297,28 +298,44 @@ static unsigned char *asm_mv(Inst *inst, Code *code) { return code->buf; } -static unsigned char *asm_li(Inst *inst, Code *code) { +static void li_sub(Inst *inst, Code *code, int64_t imm) { int rd = inst->opr1.reg.no; - int64_t imm =inst->opr2.immediate; if (is_im6(imm)) { C_LI(rd, imm); } else if (is_im12(imm)) { P_LI(rd, imm); } else if (is_im32(imm)) { - int h = imm >> 12, l = imm & 0xfff; + int l = imm & 0xfff; if (l >= 0x800) { l = l - 0x1000; - h += 1; + imm += 1 << 12; } - C_LUI(rd, h); + if (is_im6(imm >> 12)) + C_LUI(rd, imm); + else + W_LUI(rd, imm); if (is_im6(l)) C_ADDIW(rd, l); else W_ADDIW(rd, rd, l); } else { - // TODO: - return NULL; + int32_t l = (int32_t)imm & ((1 << 12) - 1); + imm >>= 12; + if (l >= (1 << 11)) { + l = l - (1 << 12); + ++imm; + } + li_sub(inst, code, imm); + C_SLLI(rd, 12); + if (is_im6(l)) + C_ADDI(rd, l); + else + W_ADDI(rd, rd, l); } +} + +static unsigned char *asm_li(Inst *inst, Code *code) { + li_sub(inst, code, inst->opr2.immediate); return code->buf; } diff --git a/src/as/asm_code.h b/src/as/asm_code.h index 790ed1e12..b036a1bfe 100644 --- a/src/as/asm_code.h +++ b/src/as/asm_code.h @@ -13,7 +13,11 @@ typedef struct Code { Inst *inst; char flag; char len; +#if XCC_TARGET_ARCH == XCC_ARCH_RISCV64 + unsigned char buf[26]; +#else unsigned char buf[14]; +#endif } Code; void assemble_inst(Inst *inst, const ParseInfo *info, Code *code); From d69d99fc78316e6295d63b8b716de2f922239988 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Mon, 22 Apr 2024 18:43:51 +0900 Subject: [PATCH 13/25] Relocation for data section --- include/elf.h | 1 + src/as/arch/riscv64/ir_asm.c | 21 ++++++++++++++++++++- src/as/as.c | 11 ++++++++--- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/include/elf.h b/include/elf.h index 4e629beba..f150dc28d 100644 --- a/include/elf.h +++ b/include/elf.h @@ -147,6 +147,7 @@ typedef struct { #define R_X86_64_PC32 (2) /* PC relative 32 bit signed */ #define R_X86_64_PLT32 (4) /* 32 bit PLT address */ +#define R_RISCV_64 (2) #define R_RISCV_BRANCH (16) #define R_RISCV_JAL (17) #define R_RISCV_CALL (18) diff --git a/src/as/arch/riscv64/ir_asm.c b/src/as/arch/riscv64/ir_asm.c index 68572a425..0989f6c2f 100644 --- a/src/as/arch/riscv64/ir_asm.c +++ b/src/as/arch/riscv64/ir_asm.c @@ -280,7 +280,26 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * } } break; - default: + case IR_EXPR_BYTE: + case IR_EXPR_SHORT: + case IR_EXPR_LONG: + case IR_EXPR_QUAD: + { + Value value = calc_expr(label_table, ir->expr); + assert(value.label != NULL); + UnresolvedInfo *info = malloc_or_die(sizeof(*info)); + info->kind = UNRES_ABS64; // TODO: + info->label = value.label; + info->src_section = sec; + info->offset = address - start_address; + info->add = value.offset; + vec_push(unresolved, info); + } + break; + case IR_LABEL: + case IR_DATA: + case IR_BSS: + case IR_ALIGN: break; } } diff --git a/src/as/as.c b/src/as/as.c index be40a4896..8c5652115 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -237,17 +237,22 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { break; case UNRES_ABS64: { +#if XCC_TARGET_ARCH == XCC_ARCH_RISCV64 + const int type = R_RISCV_64; +#else // #elif XCC_TARGET_ARCH == XCC_ARCH_X64 + const int type = R_X86_64_64; +#endif LabelInfo *label = table_get(label_table, u->label); - if (label == NULL || label->flag & LF_GLOBAL) { + if (label == NULL || label->flag & (LF_GLOBAL | LF_REFERRED)) { int symidx = symtab_find(&symtab, u->label); assert(symidx >= 0); rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(symidx, R_X86_64_64); + rela->r_info = ELF64_R_INFO(symidx, type); rela->r_addend = u->add; } else { rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(label->section + 1, R_X86_64_64); + rela->r_info = ELF64_R_INFO(label->section + 1, type); rela->r_addend = u->add + (label->address - section_start_addresses[label->section]); } } From fb4d681e19caf211772b6f9694c70ca6e82187e5 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 23 Apr 2024 10:33:11 +0900 Subject: [PATCH 14/25] FP arithmetic instructions --- src/as/arch/aarch64/inst.h | 2 +- src/as/arch/riscv64/asm_code.c | 29 +++++ src/as/arch/riscv64/inst.h | 13 ++- src/as/arch/riscv64/parse_riscv64.c | 161 +++++++++++++++++----------- src/as/arch/x64/inst.h | 4 +- 5 files changed, 139 insertions(+), 70 deletions(-) diff --git a/src/as/arch/aarch64/inst.h b/src/as/arch/aarch64/inst.h index cfddd4262..a93756f5e 100644 --- a/src/as/arch/aarch64/inst.h +++ b/src/as/arch/aarch64/inst.h @@ -14,7 +14,7 @@ enum Opcode { }; enum RegType { - NOREG, + NOREG = -1, // 32bit W0, W1, W2, W3, W4, W5, W6, W7, W8, W9, W10, W11, W12, W13, W14, W15, diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 9ab81fc9c..7d3df3ac0 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -106,6 +106,11 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_JALR(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x67) #define W_BXX(funct3, rs1, rs2, ofs) STYPE(ofs, rs2, rs1, funct3, 0x63) +#define W_FADD_D(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x53) +#define W_FSUB_D(rd, rs1, rs2) RTYPE(0x05, rs2, rs1, 0x07, rd, 0x53) +#define W_FMUL_D(rd, rs1, rs2) RTYPE(0x09, rs2, rs1, 0x07, rd, 0x53) +#define W_FDIV_D(rd, rs1, rs2) RTYPE(0x0d, rs2, rs1, 0x07, rd, 0x53) + #define C_MV(rd, rs) MAKE_CODE16(inst, code, 0x8002 | ((rd) << 7) | ((rs) << 2)) #define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) #define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 17, 17) << 12) | ((rd) << 7) | (IMM(imm, 16, 12) << 2)) @@ -495,6 +500,24 @@ static unsigned char *asm_ret(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_3fr(Inst *inst, Code *code) { + assert(inst->opr1.type == FREG); + assert(inst->opr2.type == FREG); + assert(inst->opr3.type == FREG); + int rd = inst->opr1.freg; + int rs1 = inst->opr2.freg; + int rs2 = inst->opr3.freg; + + switch (inst->op) { + case FADD_D: W_FADD_D(rd, rs1, rs2); break; + case FSUB_D: W_FSUB_D(rd, rs1, rs2); break; + case FMUL_D: W_FMUL_D(rd, rs1, rs2); break; + case FDIV_D: W_FDIV_D(rd, rs1, rs2); break; + default: assert(false); return NULL; + } + return code->buf; +} + //////////////////////////////////////////////// typedef unsigned char *(*AsmInstFunc)(Inst *inst, Code *code); @@ -530,6 +553,10 @@ static const AsmInstTable table_bxx[] ={ {asm_bxx, REG, REG, DIRECT}, {NULL} }; +static const AsmInstTable table_3fr[] ={ + {asm_3fr, FREG, FREG, FREG}, + {NULL} }; + static const AsmInstTable *table[] = { [NOOP] = (const AsmInstTable[]){ {asm_noop, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, [MV] = (const AsmInstTable[]){ {asm_mv, REG, REG, NOOPERAND}, {NULL} }, @@ -563,6 +590,8 @@ static const AsmInstTable *table[] = { [BLTU] = table_bxx, [BGEU] = table_bxx, [CALL] = (const AsmInstTable[]){ {asm_call_d, DIRECT, NOOPERAND, NOOPERAND}, {NULL} }, [RET] = (const AsmInstTable[]){ {asm_ret, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, + + [FADD_D] = table_3fr, [FSUB_D] = table_3fr, [FMUL_D] = table_3fr, [FDIV_D] = table_3fr, }; void assemble_inst(Inst *inst, const ParseInfo *info, Code *code) { diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index dff842887..26883ead6 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -39,11 +39,12 @@ enum Opcode { BEQ, BNE, BLT, BGE, BLTU, BGEU, CALL, RET, + + FADD_D, FSUB_D, FMUL_D, FDIV_D, }; enum RegType { - NOREG, - + NOREG = -1, X0, X1, X2, X3, X4, X5, X6, X7, X8, X9, X10, X11, X12, X13, X14, X15, X16, X17, X18, X19, X20, X21, X22, X23, X24, X25, X26, X27, X28, X29, X30, X31, }; @@ -52,12 +53,19 @@ typedef struct { char no; // 0~31 } Reg; +enum FRegType { + NOFREG = -1, + F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, + F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31, +}; + enum OperandType { NOOPERAND, REG, // reg IMMEDIATE, // 1234 DIRECT, // foobar + 345 INDIRECT, // ofs(reg) + FREG, // freg }; typedef struct { @@ -72,6 +80,7 @@ typedef struct { Expr *offset; Reg reg; } indirect; + enum FRegType freg; }; } Operand; diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 6d089aed9..d5d65c2d1 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -41,6 +41,8 @@ static const char *kOpTable[] = { "beq", "bne", "blt", "bge", "bltu", "bgeu", "call", "ret", + + "fadd.d", "fsub.d", "fmul.d", "fdiv.d", }; #define ZEROREG X0 @@ -80,72 +82,81 @@ static const struct { const char *name; enum RegType reg; } kRegisters[] = { - {"x0", X0}, - {"x1", X1}, - {"x2", X2}, - {"x3", X3}, - {"x4", X4}, - {"x5", X5}, - {"x6", X6}, - {"x7", X7}, - {"x8", X8}, - {"x9", X9}, - {"x10", X10}, - {"x11", X11}, - {"x12", X12}, - {"x13", X13}, - {"x14", X14}, - {"x15", X15}, - {"x16", X16}, - {"x17", X17}, - {"x18", X18}, - {"x19", X19}, - {"x20", X20}, - {"x21", X21}, - {"x22", X22}, - {"x23", X23}, - {"x24", X24}, - {"x25", X25}, - {"x26", X26}, - {"x27", X27}, - {"x28", X28}, - {"x29", X29}, - {"x30", X30}, - {"x31", X31}, + {"x0", X0}, {"x1", X1}, {"x2", X2}, {"x3", X3}, + {"x4", X4}, {"x5", X5}, {"x6", X6}, {"x7", X7}, + {"x8", X8}, {"x9", X9}, {"x10", X10}, {"x11", X11}, + {"x12", X12}, {"x13", X13}, {"x14", X14}, {"x15", X15}, + {"x16", X16}, {"x17", X17}, {"x18", X18}, {"x19", X19}, + {"x20", X20}, {"x21", X21}, {"x22", X22}, {"x23", X23}, + {"x24", X24}, {"x25", X25}, {"x26", X26}, {"x27", X27}, + {"x28", X28}, {"x29", X29}, {"x30", X30}, {"x31", X31}, + + // Alias + {"zero", ZEROREG}, {"ra", RA}, {"sp", SP}, {"gp", GP}, + {"tp", TP}, {"t0", T0}, {"t1", T1}, {"t2", T2}, + {"fp", FP}, {"s1", S1}, {"a0", A0}, {"a1", A1}, + {"a2", A2}, {"a3", A3}, {"a4", A4}, {"a5", A5}, + {"a6", A6}, {"a7", A7}, {"s2", S2}, {"s3", S3}, + {"s4", S4}, {"s5", S5}, {"s6", S6}, {"s7", S7}, + {"s8", S8}, {"s9", S9}, {"s10", S10}, {"s11", S11}, + {"t3", T3}, {"t4", T4}, {"t5", T5}, {"t6", T6}, +}; + +#define FT0 F0 +#define FT1 F1 +#define FT2 F2 +#define FT3 F3 +#define FT4 F4 +#define FT5 F5 +#define FT6 F6 +#define FT7 F7 +#define FS0 F8 +#define FS1 F9 +#define FA0 F10 +#define FA1 F11 +#define FA2 F12 +#define FA3 F13 +#define FA4 F14 +#define FA5 F15 +#define FA6 F16 +#define FA7 F17 +#define FS2 F18 +#define FS3 F19 +#define FS4 F20 +#define FS5 F21 +#define FS6 F22 +#define FS7 F23 +#define FS8 F24 +#define FS9 F25 +#define FS10 F26 +#define FS11 F27 +#define FT8 F28 +#define FT9 F29 +#define FT10 F30 +#define FT11 F31 + +static const struct { + const char *name; + enum FRegType reg; +} kFRegisters[] = { + {"f0", F0}, {"f1", F1}, {"f2", F2}, {"f3", F3}, + {"f4", F4}, {"f5", F5}, {"f6", F6}, {"f7", F7}, + {"f8", F8}, {"f9", F9}, {"f10", F10}, {"f11", F11}, + {"f12", F12}, {"f13", F13}, {"f14", F14}, {"f15", F15}, + {"f16", F16}, {"f17", F17}, {"f18", F18}, {"f19", F19}, + {"f20", F20}, {"f21", F21}, {"f22", F22}, {"f23", F23}, + {"f24", F24}, {"f25", F25}, {"f26", F26}, {"f27", F27}, + {"f28", F28}, {"f29", F29}, {"f30", F30}, {"f31", F31}, // Alias - {"zero", ZEROREG}, - {"ra", RA}, - {"sp", SP}, - {"gp", GP}, - {"tp", TP}, - {"t0", T0}, - {"t1", T1}, - {"t2", T2}, - {"fp", FP}, - {"s1", S1}, - {"a0", A0}, - {"a1", A1}, - {"a2", A2}, - {"a3", A3}, - {"a4", A4}, - {"a5", A5}, - {"a6", A6}, - {"a7", A7}, - {"s2", S2}, - {"s3", S3}, - {"s4", S4}, - {"s5", S5}, - {"s6", S6}, - {"s7", S7}, - {"s8", S8}, - {"s9", S9}, - {"s10", S10}, - {"s11", S11}, - {"t3", T3}, - {"t4", T4}, - {"t5", T5}, - {"t6", T6}, + {"ft0", FT0}, {"ft1", FT1}, {"ft2", FT2}, {"ft3", FT3}, + {"ft4", FT4}, {"ft5", FT5}, {"ft6", FT6}, {"ft7", FT7}, + {"fs0", FS0}, {"fs1", FS1}, {"fa0", FA0}, {"fa1", FA1}, + {"fa2", FA2}, {"fa3", FA3}, {"fa4", FA4}, {"fa5", FA5}, + {"fa6", FA6}, {"fa7", FA7}, {"fs2", FS2}, {"fs3", FS3}, + {"fs4", FS4}, {"fs5", FS5}, {"fs6", FS6}, {"fs7", FS7}, + {"fs8", FS8}, {"fs9", FS9}, {"fs10", FS10}, {"fs11", FS11}, + {"ft8", FT8}, {"ft9", FT9}, {"ft10", FT10}, {"ft11", FT11}, }; static int find_match_index(const char **pp, const char **table, size_t count) { @@ -185,6 +196,19 @@ static enum RegType find_register(const char **pp) { return NOREG; } +static enum FRegType find_fregister(const char **pp) { + const char *p = *pp; + for (int i = 0; i < (int)ARRAY_SIZE(kFRegisters); ++i) { + const char *name = kFRegisters[i].name; + size_t n = strlen(name); + if (strncmp(p, name, n) == 0 && !is_label_chr(p[n])) { + *pp = p + n; + return kFRegisters[i].reg; + } + } + return NOFREG; +} + static bool parse_indirect_register(ParseInfo *info, Expr *offset, Operand *operand) { // Already read "(". enum RegType base_reg = find_register(&info->p); @@ -210,7 +234,14 @@ static bool parse_operand(ParseInfo *info, Operand *operand) { enum RegType reg = find_register(&info->p); if (reg != NOREG) { operand->type = REG; - operand->reg.no = reg - ZEROREG; + operand->reg.no = reg - X0; + return true; + } + + enum FRegType freg = find_fregister(&info->p); + if (freg != NOFREG) { + operand->type = FREG; + operand->freg = freg; return true; } diff --git a/src/as/arch/x64/inst.h b/src/as/arch/x64/inst.h index b067e1bb4..79443355b 100644 --- a/src/as/arch/x64/inst.h +++ b/src/as/arch/x64/inst.h @@ -118,7 +118,7 @@ enum Opcode { }; enum RegType { - NOREG, + NOREG = -1, // 8bit AL, CL, DL, BL, @@ -151,7 +151,7 @@ enum RegType { }; enum RegXmmType { - NOREGXMM, + NOREGXMM = -1, XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7, XMM8, XMM9, XMM10, XMM11, XMM12, XMM13, XMM14, XMM15, }; From 7a34aa51997b34b372086a604c1a300a8005d68a Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 23 Apr 2024 10:46:30 +0900 Subject: [PATCH 15/25] FLD, FSD --- src/as/arch/riscv64/asm_code.c | 72 +++++++++++++++++++++++++++++ src/as/arch/riscv64/inst.h | 3 ++ src/as/arch/riscv64/parse_riscv64.c | 1 + 3 files changed, 76 insertions(+) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 7d3df3ac0..0993774d4 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -110,6 +110,10 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_FSUB_D(rd, rs1, rs2) RTYPE(0x05, rs2, rs1, 0x07, rd, 0x53) #define W_FMUL_D(rd, rs1, rs2) RTYPE(0x09, rs2, rs1, 0x07, rd, 0x53) #define W_FDIV_D(rd, rs1, rs2) RTYPE(0x0d, rs2, rs1, 0x07, rd, 0x53) +#define W_FLD(rd, ofs, rs) ITYPE(ofs, rs, 0x03, rd, 0x07) +#define W_FLW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x07) +#define W_FSD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x27) +#define W_FSW(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x02, 0x27) #define C_MV(rd, rs) MAKE_CODE16(inst, code, 0x8002 | ((rd) << 7) | ((rs) << 2)) #define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) @@ -140,6 +144,11 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define C_BEQZ(rs) MAKE_CODE16(inst, code, 0xc001 | (to_rvc_reg(rs) << 7)) #define C_BNEZ(rs) MAKE_CODE16(inst, code, 0xe001 | (to_rvc_reg(rs) << 7)) +#define C_FLD(rd, imm, rs) MAKE_CODE16(inst, code, 0x2000 | (IMM(imm, 5, 3) << 10) | (to_rvc_freg(rs) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_freg(rd) << 2)) +#define C_FSD(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xa000 | (IMM(imm, 5, 3) << 10) | (to_rvc_freg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_freg(rs2) << 2)) +#define C_FLDSP(rd, imm) MAKE_CODE16(inst, code, 0x2002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) +#define C_FSDSP(rs, imm) MAKE_CODE16(inst, code, 0xa002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) + #define P_RET() C_JR(RA) #define P_LI(rd, imm) W_ADDI(rd, ZERO, imm) #define P_NEG(rd, rs) W_SUB(rd, ZERO, rs) @@ -518,6 +527,60 @@ static unsigned char *asm_3fr(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_fld(Inst *inst, Code *code) { + int rd = inst->opr1.freg; + Expr *offset = inst->opr2.indirect.offset; + if (offset == NULL || offset->kind == EX_FIXNUM) { + int64_t ofs = offset != NULL ? offset->fixnum : 0; + int rs = inst->opr2.indirect.reg.no; + if (inst->op == FLD) { + if (ofs >= 0 && ofs < (1 << 9) && (ofs & 7) == 0 && rs == SP) { + C_FLDSP(rd, ofs); + return code->buf; + } + if (ofs >= 0 && ofs < (1 << 8) && (ofs & 7) == 0 && is_rvc_freg(rd) && is_rvc_freg(rs)) { + C_FLD(rd, ofs, rs); + return code->buf; + } + } + // TODO: Check offset range. + switch (inst->op) { + case FLD: W_FLD(rd, ofs, rs); break; + case FLW: W_FLW(rd, ofs, rs); break; + default: assert(false); break; + } + return code->buf; + } + return NULL; +} + +static unsigned char *asm_fsd(Inst *inst, Code *code) { + Expr *offset = inst->opr2.indirect.offset; + if (offset == NULL || offset->kind == EX_FIXNUM) { + int64_t ofs = offset != NULL ? offset->fixnum : 0; + int rs2 = inst->opr1.freg; + int rs1 = inst->opr2.indirect.reg.no; + if (inst->op == FLD) { + if (ofs >= 0 && ofs < (1 << 9) && (ofs & 7) == 0 && rs1 == SP) { + C_FSDSP(rs2, ofs); + return code->buf; + } + if (ofs >= 0 && ofs < (1 << 8) && (ofs & 7) == 0 && is_rvc_freg(rs1) && is_rvc_freg(rs2)) { + C_FSD(rs2, ofs, rs1); + return code->buf; + } + } + // TODO: Check offset range. + switch (inst->op) { + case FSD: W_FSD(rs2, ofs, rs1); break; + case FSW: W_FSW(rs2, ofs, rs1); break; + default: assert(false); break; + } + return code->buf; + } + return NULL; +} + //////////////////////////////////////////////// typedef unsigned char *(*AsmInstFunc)(Inst *inst, Code *code); @@ -557,6 +620,14 @@ static const AsmInstTable table_3fr[] ={ {asm_3fr, FREG, FREG, FREG}, {NULL} }; +static const AsmInstTable table_fld[] ={ + {asm_fld, FREG, INDIRECT, NOOPERAND}, + {NULL} }; + +static const AsmInstTable table_fsd[] ={ + {asm_fsd, FREG, INDIRECT, NOOPERAND}, + {NULL} }; + static const AsmInstTable *table[] = { [NOOP] = (const AsmInstTable[]){ {asm_noop, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, [MV] = (const AsmInstTable[]){ {asm_mv, REG, REG, NOOPERAND}, {NULL} }, @@ -592,6 +663,7 @@ static const AsmInstTable *table[] = { [RET] = (const AsmInstTable[]){ {asm_ret, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, [FADD_D] = table_3fr, [FSUB_D] = table_3fr, [FMUL_D] = table_3fr, [FDIV_D] = table_3fr, + [FLD] = table_fld, [FLW] = table_fld, [FSD] = table_fsd, [FSW] = table_fsd, }; void assemble_inst(Inst *inst, const ParseInfo *info, Code *code) { diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 26883ead6..98b65adef 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -41,6 +41,7 @@ enum Opcode { RET, FADD_D, FSUB_D, FMUL_D, FDIV_D, + FLD, FLW, FSD, FSW, }; enum RegType { @@ -93,3 +94,5 @@ typedef struct Inst { inline bool is_rvc_reg(int reg) { return reg >= 8 && reg <= 15; } // X8~X15 inline int to_rvc_reg(int reg) { return reg - 8; } +#define is_rvc_freg is_rvc_reg +#define to_rvc_freg to_rvc_reg diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index d5d65c2d1..834f8b1c2 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -43,6 +43,7 @@ static const char *kOpTable[] = { "ret", "fadd.d", "fsub.d", "fmul.d", "fdiv.d", + "fld", "flw", "fsd", "fsw", }; #define ZEROREG X0 From 2bd63bfeaba7133ad09dad2b26ab493ba81aa090 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 23 Apr 2024 11:05:49 +0900 Subject: [PATCH 16/25] fmv.d, fneg.d Expanded to `fsgnj`. --- src/as/arch/riscv64/asm_code.c | 24 ++++++++++++++++++++++++ src/as/arch/riscv64/inst.h | 1 + src/as/arch/riscv64/parse_riscv64.c | 1 + 3 files changed, 26 insertions(+) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 0993774d4..d662463f8 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -114,6 +114,8 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_FLW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x07) #define W_FSD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x27) #define W_FSW(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x02, 0x27) +#define W_FSGNJ_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x00, rd, 0x53) +#define W_FSGNJN_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x01, rd, 0x53) #define C_MV(rd, rs) MAKE_CODE16(inst, code, 0x8002 | ((rd) << 7) | ((rs) << 2)) #define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) @@ -164,6 +166,9 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define P_SLTZ(rd, rs) W_SLT(rd, rs, ZERO) #define P_SGTZ(rd, rs) W_SLT(rd, ZERO, rs) +#define P_FMV_D(rd, rs) W_FSGNJ_D(rd, rs, rs) +#define P_FNEG_D(rd, rs) W_FSGNJN_D(rd, rs, rs) + extern inline bool is_rvc_reg(int reg); extern inline int to_rvc_reg(int reg); @@ -527,6 +532,20 @@ static unsigned char *asm_3fr(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_2fr(Inst *inst, Code *code) { + assert(inst->opr1.type == FREG); + assert(inst->opr2.type == FREG); + int rd = inst->opr1.freg; + int rs = inst->opr2.freg; + + switch (inst->op) { + case FMV_D: P_FMV_D(rd, rs); break; + case FNEG_D: P_FNEG_D(rd, rs); break; + default: assert(false); return NULL; + } + return code->buf; +} + static unsigned char *asm_fld(Inst *inst, Code *code) { int rd = inst->opr1.freg; Expr *offset = inst->opr2.indirect.offset; @@ -620,6 +639,10 @@ static const AsmInstTable table_3fr[] ={ {asm_3fr, FREG, FREG, FREG}, {NULL} }; +static const AsmInstTable table_2fr[] ={ + {asm_2fr, FREG, FREG, NOOPERAND}, + {NULL} }; + static const AsmInstTable table_fld[] ={ {asm_fld, FREG, INDIRECT, NOOPERAND}, {NULL} }; @@ -663,6 +686,7 @@ static const AsmInstTable *table[] = { [RET] = (const AsmInstTable[]){ {asm_ret, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, [FADD_D] = table_3fr, [FSUB_D] = table_3fr, [FMUL_D] = table_3fr, [FDIV_D] = table_3fr, + [FMV_D] = table_2fr, [FNEG_D] = table_2fr, [FLD] = table_fld, [FLW] = table_fld, [FSD] = table_fsd, [FSW] = table_fsd, }; diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 98b65adef..5c757d7a9 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -41,6 +41,7 @@ enum Opcode { RET, FADD_D, FSUB_D, FMUL_D, FDIV_D, + FMV_D, FNEG_D, FLD, FLW, FSD, FSW, }; diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 834f8b1c2..6afd303f7 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -43,6 +43,7 @@ static const char *kOpTable[] = { "ret", "fadd.d", "fsub.d", "fmul.d", "fdiv.d", + "fmv.d", "fneg.d", "fld", "flw", "fsd", "fsw", }; From 6203b28320f548948c4fee543caf9318684f9745 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 23 Apr 2024 14:34:51 +0900 Subject: [PATCH 17/25] fcmp --- src/as/arch/riscv64/asm_code.c | 31 +++++++++++++++++++++++++++++ src/as/arch/riscv64/inst.h | 2 ++ src/as/arch/riscv64/parse_riscv64.c | 2 ++ 3 files changed, 35 insertions(+) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index d662463f8..45082279f 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -110,6 +110,12 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_FSUB_D(rd, rs1, rs2) RTYPE(0x05, rs2, rs1, 0x07, rd, 0x53) #define W_FMUL_D(rd, rs1, rs2) RTYPE(0x09, rs2, rs1, 0x07, rd, 0x53) #define W_FDIV_D(rd, rs1, rs2) RTYPE(0x0d, rs2, rs1, 0x07, rd, 0x53) +#define W_FEQ_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x02, rd, 0x53) +#define W_FLT_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x01, rd, 0x53) +#define W_FLE_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x00, rd, 0x53) +#define W_FEQ_S(rd, rs1, rs2) RTYPE(0x50, rs2, rs1, 0x02, rd, 0x53) +#define W_FLT_S(rd, rs1, rs2) RTYPE(0x50, rs2, rs1, 0x01, rd, 0x53) +#define W_FLE_S(rd, rs1, rs2) RTYPE(0x50, rs2, rs1, 0x00, rd, 0x53) #define W_FLD(rd, ofs, rs) ITYPE(ofs, rs, 0x03, rd, 0x07) #define W_FLW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x07) #define W_FSD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x27) @@ -546,6 +552,25 @@ static unsigned char *asm_2fr(Inst *inst, Code *code) { return code->buf; } +static unsigned char *asm_fcmp(Inst *inst, Code *code) { + assert(inst->opr1.type == REG); + assert(inst->opr2.type == FREG); + assert(inst->opr3.type == FREG); + int rd = inst->opr1.freg; + int rs1 = inst->opr2.freg; + int rs2 = inst->opr3.freg; + switch (inst->op) { + case FEQ_D: W_FEQ_D(rd, rs1, rs2); break; + case FLT_D: W_FLT_D(rd, rs1, rs2); break; + case FLE_D: W_FLE_D(rd, rs1, rs2); break; + case FEQ_S: W_FEQ_S(rd, rs1, rs2); break; + case FLT_S: W_FLT_S(rd, rs1, rs2); break; + case FLE_S: W_FLE_S(rd, rs1, rs2); break; + default: assert(false); return NULL; + } + return code->buf; +} + static unsigned char *asm_fld(Inst *inst, Code *code) { int rd = inst->opr1.freg; Expr *offset = inst->opr2.indirect.offset; @@ -643,6 +668,10 @@ static const AsmInstTable table_2fr[] ={ {asm_2fr, FREG, FREG, NOOPERAND}, {NULL} }; +static const AsmInstTable table_fcmp[] ={ + {asm_fcmp, REG, FREG, FREG}, + {NULL} }; + static const AsmInstTable table_fld[] ={ {asm_fld, FREG, INDIRECT, NOOPERAND}, {NULL} }; @@ -687,6 +716,8 @@ static const AsmInstTable *table[] = { [FADD_D] = table_3fr, [FSUB_D] = table_3fr, [FMUL_D] = table_3fr, [FDIV_D] = table_3fr, [FMV_D] = table_2fr, [FNEG_D] = table_2fr, + [FEQ_D] = table_fcmp, [FLT_D] = table_fcmp, [FLE_D] = table_fcmp, + [FEQ_S] = table_fcmp, [FLT_S] = table_fcmp, [FLE_S] = table_fcmp, [FLD] = table_fld, [FLW] = table_fld, [FSD] = table_fsd, [FSW] = table_fsd, }; diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 5c757d7a9..34acdc98d 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -42,6 +42,8 @@ enum Opcode { FADD_D, FSUB_D, FMUL_D, FDIV_D, FMV_D, FNEG_D, + FEQ_D, FLT_D, FLE_D, + FEQ_S, FLT_S, FLE_S, FLD, FLW, FSD, FSW, }; diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 6afd303f7..b792e0a79 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -44,6 +44,8 @@ static const char *kOpTable[] = { "fadd.d", "fsub.d", "fmul.d", "fdiv.d", "fmv.d", "fneg.d", + "feq.d", "flt.d", "fle.d", + "feq.s", "flt.s", "fle.s", "fld", "flw", "fsd", "fsw", }; From 314237c70660f304191459d6b5c53e243ccc4004 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 23 Apr 2024 15:54:58 +0900 Subject: [PATCH 18/25] fcvt --- src/as/arch/riscv64/asm_code.c | 61 +++++++++++++++++++++++++++++ src/as/arch/riscv64/inst.h | 15 +++++++ src/as/arch/riscv64/parse_riscv64.c | 40 ++++++++++++++++++- 3 files changed, 114 insertions(+), 2 deletions(-) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 45082279f..e91142459 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -123,6 +123,19 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_FSGNJ_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x00, rd, 0x53) #define W_FSGNJN_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x01, rd, 0x53) +#define W_FCVT_D_W(rd, rs) RTYPE(0x69, 0, rs, 0x00, rd, 0x53) +#define W_FCVT_D_WU(rd, rs) RTYPE(0x69, 1, rs, 0x00, rd, 0x53) +#define W_FCVT_D_L(rd, rs) RTYPE(0x69, 2, rs, 0x07, rd, 0x53) +#define W_FCVT_D_LU(rd, rs) RTYPE(0x69, 3, rs, 0x07, rd, 0x53) + +#define W_FCVT_W_D(rd, rs, rm) RTYPE(0x61, 0, rs, rm, rd, 0x53) +#define W_FCVT_WU_D(rd, rs, rm) RTYPE(0x61, 1, rs, rm, rd, 0x53) +#define W_FCVT_L_D(rd, rs, rm) RTYPE(0x61, 2, rs, rm, rd, 0x53) +#define W_FCVT_LU_D(rd, rs, rm) RTYPE(0x61, 3, rs, rm, rd, 0x53) + +#define W_FCVT_D_S(rd, rs) RTYPE(0x21, 0, rs, 0x00, rd, 0x53) +#define W_FCVT_S_D(rd, rs) RTYPE(0x20, 1, rs, 0x07, rd, 0x53) + #define C_MV(rd, rs) MAKE_CODE16(inst, code, 0x8002 | ((rd) << 7) | ((rs) << 2)) #define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) #define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 17, 17) << 12) | ((rd) << 7) | (IMM(imm, 16, 12) << 2)) @@ -547,6 +560,8 @@ static unsigned char *asm_2fr(Inst *inst, Code *code) { switch (inst->op) { case FMV_D: P_FMV_D(rd, rs); break; case FNEG_D: P_FNEG_D(rd, rs); break; + case FCVT_D_S: W_FCVT_D_S(rd, rs); break; + case FCVT_S_D: W_FCVT_S_D(rd, rs); break; default: assert(false); return NULL; } return code->buf; @@ -625,6 +640,37 @@ static unsigned char *asm_fsd(Inst *inst, Code *code) { return NULL; } +static unsigned char *asm_fi(Inst *inst, Code *code) { + assert(inst->opr1.type == FREG); + assert(inst->opr2.type == REG); + int rd = inst->opr1.freg; + int rs = inst->opr2.reg.no; + switch (inst->op) { + case FCVT_D_W: W_FCVT_D_W(rd, rs); break; + case FCVT_D_WU: W_FCVT_D_WU(rd, rs); break; + case FCVT_D_L: W_FCVT_D_L(rd, rs); break; + case FCVT_D_LU: W_FCVT_D_LU(rd, rs); break; + default: assert(false); return NULL; + } + return code->buf; +} + +static unsigned char *asm_if(Inst *inst, Code *code) { + assert(inst->opr1.type == REG); + assert(inst->opr2.type == FREG); + int rd = inst->opr1.reg.no; + int rs = inst->opr2.freg; + int rm = inst->opr3.type == ROUNDMODE ? inst->opr3.roundmode : 0; + switch (inst->op) { + case FCVT_W_D: W_FCVT_W_D(rd, rs, rm); break; + case FCVT_WU_D: W_FCVT_WU_D(rd, rs, rm); break; + case FCVT_L_D: W_FCVT_L_D(rd, rs, rm); break; + case FCVT_LU_D: W_FCVT_LU_D(rd, rs, rm); break; + default: assert(false); return NULL; + } + return code->buf; +} + //////////////////////////////////////////////// typedef unsigned char *(*AsmInstFunc)(Inst *inst, Code *code); @@ -680,6 +726,15 @@ static const AsmInstTable table_fsd[] ={ {asm_fsd, FREG, INDIRECT, NOOPERAND}, {NULL} }; +static const AsmInstTable table_fi[] ={ + {asm_fi, FREG, REG, NOOPERAND}, + {NULL} }; + +static const AsmInstTable table_if[] ={ + {asm_if, REG, FREG, NOOPERAND}, + {asm_if, REG, FREG, ROUNDMODE}, + {NULL} }; + static const AsmInstTable *table[] = { [NOOP] = (const AsmInstTable[]){ {asm_noop, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, [MV] = (const AsmInstTable[]){ {asm_mv, REG, REG, NOOPERAND}, {NULL} }, @@ -719,6 +774,12 @@ static const AsmInstTable *table[] = { [FEQ_D] = table_fcmp, [FLT_D] = table_fcmp, [FLE_D] = table_fcmp, [FEQ_S] = table_fcmp, [FLT_S] = table_fcmp, [FLE_S] = table_fcmp, [FLD] = table_fld, [FLW] = table_fld, [FSD] = table_fsd, [FSW] = table_fsd, + + [FCVT_D_W] = table_fi, [FCVT_D_WU] = table_fi, + [FCVT_D_L] = table_fi, [FCVT_D_LU] = table_fi, + [FCVT_W_D] = table_if, [FCVT_WU_D] = table_if, + [FCVT_L_D] = table_if, [FCVT_LU_D] = table_if, + [FCVT_D_S] = table_2fr, [FCVT_S_D] = table_2fr, }; void assemble_inst(Inst *inst, const ParseInfo *info, Code *code) { diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 34acdc98d..6ef10e0aa 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -45,6 +45,10 @@ enum Opcode { FEQ_D, FLT_D, FLE_D, FEQ_S, FLT_S, FLE_S, FLD, FLW, FSD, FSW, + + FCVT_D_W, FCVT_D_WU, FCVT_D_L, FCVT_D_LU, + FCVT_W_D, FCVT_WU_D, FCVT_L_D, FCVT_LU_D, + FCVT_D_S, FCVT_S_D, }; enum RegType { @@ -63,6 +67,15 @@ enum FRegType { F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31, }; +enum RoundMode { + NOROUND = -1, + RNE, // Round to Nearest, ties to Even + RTZ, // Round towards Zero + RDN, // Round Down (towards -Inf) + RUP, // Round Up (towards +Inf) + RMM, // Round to Nearest, ties to Max Magnitude +}; + enum OperandType { NOOPERAND, REG, // reg @@ -70,6 +83,7 @@ enum OperandType { DIRECT, // foobar + 345 INDIRECT, // ofs(reg) FREG, // freg + ROUNDMODE, // rm }; typedef struct { @@ -85,6 +99,7 @@ typedef struct { Reg reg; } indirect; enum FRegType freg; + enum RoundMode roundmode; }; } Operand; diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index b792e0a79..079569ba1 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -47,6 +47,9 @@ static const char *kOpTable[] = { "feq.d", "flt.d", "fle.d", "feq.s", "flt.s", "fle.s", "fld", "flw", "fsd", "fsw", + "fcvt.d.w", "fcvt.d.wu", "fcvt.d.l", "fcvt.d.lu", + "fcvt.w.d", "fcvt.wu.d", "fcvt.l.d", "fcvt.lu.d", + "fcvt.d.s", "fcvt.s.d", }; #define ZEROREG X0 @@ -163,6 +166,17 @@ static const struct { {"ft8", FT8}, {"ft9", FT9}, {"ft10", FT10}, {"ft11", FT11}, }; +static const struct { + const char *name; + enum RoundMode mode; +} kRoundModes[] = { + {"rne", RNE}, + {"rtz", RTZ}, + {"rdn", RDN}, + {"rup", RUP}, + {"rmm", RMM}, +}; + static int find_match_index(const char **pp, const char **table, size_t count) { const char *p = *pp; const char *start = p; @@ -213,6 +227,19 @@ static enum FRegType find_fregister(const char **pp) { return NOFREG; } +static enum RoundMode find_round_mode(const char **pp) { + const char *p = *pp; + for (int i = 0; i < (int)ARRAY_SIZE(kRoundModes); ++i) { + const char *name = kRoundModes[i].name; + size_t n = strlen(name); + if (strncmp(p, name, n) == 0 && !is_label_chr(p[n])) { + *pp = p + n; + return kRoundModes[i].mode; + } + } + return NOROUND; +} + static bool parse_indirect_register(ParseInfo *info, Expr *offset, Operand *operand) { // Already read "(". enum RegType base_reg = find_register(&info->p); @@ -234,7 +261,16 @@ static bool parse_indirect_register(ParseInfo *info, Expr *offset, Operand *oper return true; } -static bool parse_operand(ParseInfo *info, Operand *operand) { +static bool parse_operand(ParseInfo *info, Operand *operand, bool search_round_mode) { + if (search_round_mode) { + enum RoundMode roundmode = find_round_mode(&info->p); + if (roundmode != NOROUND) { + operand->type = ROUNDMODE; + operand->roundmode = roundmode; + return true; + } + } + enum RegType reg = find_register(&info->p); if (reg != NOREG) { operand->type = REG; @@ -288,7 +324,7 @@ void parse_inst(ParseInfo *info, Line *line) { inst->op = op; if (op != NOOP) { for (int i = 0; i < (int)ARRAY_SIZE(opr_table); ++i) { - if (!parse_operand(info, opr_table[i])) + if (!parse_operand(info, opr_table[i], i >= 2)) break; info->p = skip_whitespaces(info->p); if (i == (int)ARRAY_SIZE(opr_table) - 1 || *info->p != ',') From 352b521144d90cd47838ed163b5911cc8e0ef71f Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 23 Apr 2024 21:57:24 +0900 Subject: [PATCH 19/25] fmv.x.d --- src/as/arch/riscv64/asm_code.c | 6 ++++++ src/as/arch/riscv64/inst.h | 1 + src/as/arch/riscv64/parse_riscv64.c | 1 + 3 files changed, 8 insertions(+) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index e91142459..05e67c32e 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -136,6 +136,9 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_FCVT_D_S(rd, rs) RTYPE(0x21, 0, rs, 0x00, rd, 0x53) #define W_FCVT_S_D(rd, rs) RTYPE(0x20, 1, rs, 0x07, rd, 0x53) +#define W_FMV_X_D(rd, rs) RTYPE(0x71, 0, rs, 0x00, rd, 0x53) +#define W_FMV_X_W(rd, rs) RTYPE(0x70, 0, rs, 0x00, rd, 0x53) + #define C_MV(rd, rs) MAKE_CODE16(inst, code, 0x8002 | ((rd) << 7) | ((rs) << 2)) #define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) #define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 17, 17) << 12) | ((rd) << 7) | (IMM(imm, 16, 12) << 2)) @@ -662,6 +665,8 @@ static unsigned char *asm_if(Inst *inst, Code *code) { int rs = inst->opr2.freg; int rm = inst->opr3.type == ROUNDMODE ? inst->opr3.roundmode : 0; switch (inst->op) { + case FMV_X_D: W_FMV_X_D(rd, rs); break; + case FMV_X_W: W_FMV_X_W(rd, rs); break; case FCVT_W_D: W_FCVT_W_D(rd, rs, rm); break; case FCVT_WU_D: W_FCVT_WU_D(rd, rs, rm); break; case FCVT_L_D: W_FCVT_L_D(rd, rs, rm); break; @@ -771,6 +776,7 @@ static const AsmInstTable *table[] = { [FADD_D] = table_3fr, [FSUB_D] = table_3fr, [FMUL_D] = table_3fr, [FDIV_D] = table_3fr, [FMV_D] = table_2fr, [FNEG_D] = table_2fr, + [FMV_X_D] = table_if, [FMV_X_W] = table_if, [FEQ_D] = table_fcmp, [FLT_D] = table_fcmp, [FLE_D] = table_fcmp, [FEQ_S] = table_fcmp, [FLT_S] = table_fcmp, [FLE_S] = table_fcmp, [FLD] = table_fld, [FLW] = table_fld, [FSD] = table_fsd, [FSW] = table_fsd, diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 6ef10e0aa..24cf579c7 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -42,6 +42,7 @@ enum Opcode { FADD_D, FSUB_D, FMUL_D, FDIV_D, FMV_D, FNEG_D, + FMV_X_D, FMV_X_W, FEQ_D, FLT_D, FLE_D, FEQ_S, FLT_S, FLE_S, FLD, FLW, FSD, FSW, diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 079569ba1..394e7266d 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -44,6 +44,7 @@ static const char *kOpTable[] = { "fadd.d", "fsub.d", "fmul.d", "fdiv.d", "fmv.d", "fneg.d", + "fmv.x.d", "fmv.x.w", "feq.d", "flt.d", "fle.d", "feq.s", "flt.s", "fle.s", "fld", "flw", "fsd", "fsw", From f595fdf405013e9c09ebf6071d74b42e4cd648c8 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 23 Apr 2024 22:23:07 +0900 Subject: [PATCH 20/25] single float --- src/as/arch/riscv64/asm_code.c | 36 +++++++++++++++++++++++++++++ src/as/arch/riscv64/inst.h | 4 ++++ src/as/arch/riscv64/parse_riscv64.c | 4 ++++ 3 files changed, 44 insertions(+) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 05e67c32e..fa4a52f2c 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -110,6 +110,10 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_FSUB_D(rd, rs1, rs2) RTYPE(0x05, rs2, rs1, 0x07, rd, 0x53) #define W_FMUL_D(rd, rs1, rs2) RTYPE(0x09, rs2, rs1, 0x07, rd, 0x53) #define W_FDIV_D(rd, rs1, rs2) RTYPE(0x0d, rs2, rs1, 0x07, rd, 0x53) +#define W_FADD_S(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x07, rd, 0x53) +#define W_FSUB_S(rd, rs1, rs2) RTYPE(0x04, rs2, rs1, 0x07, rd, 0x53) +#define W_FMUL_S(rd, rs1, rs2) RTYPE(0x08, rs2, rs1, 0x07, rd, 0x53) +#define W_FDIV_S(rd, rs1, rs2) RTYPE(0x0c, rs2, rs1, 0x07, rd, 0x53) #define W_FEQ_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x02, rd, 0x53) #define W_FLT_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x01, rd, 0x53) #define W_FLE_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x00, rd, 0x53) @@ -121,17 +125,27 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define W_FSD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x27) #define W_FSW(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x02, 0x27) #define W_FSGNJ_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x00, rd, 0x53) +#define W_FSGNJ_S(rd, rs1, rs2) RTYPE(0x10, rs2, rs1, 0x00, rd, 0x53) #define W_FSGNJN_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x01, rd, 0x53) +#define W_FSGNJN_S(rd, rs1, rs2) RTYPE(0x10, rs2, rs1, 0x01, rd, 0x53) #define W_FCVT_D_W(rd, rs) RTYPE(0x69, 0, rs, 0x00, rd, 0x53) #define W_FCVT_D_WU(rd, rs) RTYPE(0x69, 1, rs, 0x00, rd, 0x53) #define W_FCVT_D_L(rd, rs) RTYPE(0x69, 2, rs, 0x07, rd, 0x53) #define W_FCVT_D_LU(rd, rs) RTYPE(0x69, 3, rs, 0x07, rd, 0x53) +#define W_FCVT_S_W(rd, rs) RTYPE(0x68, 0, rs, 0x07, rd, 0x53) +#define W_FCVT_S_WU(rd, rs) RTYPE(0x68, 1, rs, 0x07, rd, 0x53) +#define W_FCVT_S_L(rd, rs) RTYPE(0x68, 2, rs, 0x07, rd, 0x53) +#define W_FCVT_S_LU(rd, rs) RTYPE(0x68, 3, rs, 0x07, rd, 0x53) #define W_FCVT_W_D(rd, rs, rm) RTYPE(0x61, 0, rs, rm, rd, 0x53) #define W_FCVT_WU_D(rd, rs, rm) RTYPE(0x61, 1, rs, rm, rd, 0x53) #define W_FCVT_L_D(rd, rs, rm) RTYPE(0x61, 2, rs, rm, rd, 0x53) #define W_FCVT_LU_D(rd, rs, rm) RTYPE(0x61, 3, rs, rm, rd, 0x53) +#define W_FCVT_W_S(rd, rs, rm) RTYPE(0x60, 0, rs, rm, rd, 0x53) +#define W_FCVT_WU_S(rd, rs, rm) RTYPE(0x60, 1, rs, rm, rd, 0x53) +#define W_FCVT_L_S(rd, rs, rm) RTYPE(0x60, 2, rs, rm, rd, 0x53) +#define W_FCVT_LU_S(rd, rs, rm) RTYPE(0x60, 3, rs, rm, rd, 0x53) #define W_FCVT_D_S(rd, rs) RTYPE(0x21, 0, rs, 0x00, rd, 0x53) #define W_FCVT_S_D(rd, rs) RTYPE(0x20, 1, rs, 0x07, rd, 0x53) @@ -189,7 +203,9 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { #define P_SGTZ(rd, rs) W_SLT(rd, ZERO, rs) #define P_FMV_D(rd, rs) W_FSGNJ_D(rd, rs, rs) +#define P_FMV_S(rd, rs) W_FSGNJ_S(rd, rs, rs) #define P_FNEG_D(rd, rs) W_FSGNJN_D(rd, rs, rs) +#define P_FNEG_S(rd, rs) W_FSGNJN_S(rd, rs, rs) extern inline bool is_rvc_reg(int reg); extern inline int to_rvc_reg(int reg); @@ -549,6 +565,10 @@ static unsigned char *asm_3fr(Inst *inst, Code *code) { case FSUB_D: W_FSUB_D(rd, rs1, rs2); break; case FMUL_D: W_FMUL_D(rd, rs1, rs2); break; case FDIV_D: W_FDIV_D(rd, rs1, rs2); break; + case FADD_S: W_FADD_S(rd, rs1, rs2); break; + case FSUB_S: W_FSUB_S(rd, rs1, rs2); break; + case FMUL_S: W_FMUL_S(rd, rs1, rs2); break; + case FDIV_S: W_FDIV_S(rd, rs1, rs2); break; default: assert(false); return NULL; } return code->buf; @@ -563,6 +583,8 @@ static unsigned char *asm_2fr(Inst *inst, Code *code) { switch (inst->op) { case FMV_D: P_FMV_D(rd, rs); break; case FNEG_D: P_FNEG_D(rd, rs); break; + case FMV_S: P_FMV_S(rd, rs); break; + case FNEG_S: P_FNEG_S(rd, rs); break; case FCVT_D_S: W_FCVT_D_S(rd, rs); break; case FCVT_S_D: W_FCVT_S_D(rd, rs); break; default: assert(false); return NULL; @@ -653,6 +675,10 @@ static unsigned char *asm_fi(Inst *inst, Code *code) { case FCVT_D_WU: W_FCVT_D_WU(rd, rs); break; case FCVT_D_L: W_FCVT_D_L(rd, rs); break; case FCVT_D_LU: W_FCVT_D_LU(rd, rs); break; + case FCVT_S_W: W_FCVT_S_W(rd, rs); break; + case FCVT_S_WU: W_FCVT_S_WU(rd, rs); break; + case FCVT_S_L: W_FCVT_S_L(rd, rs); break; + case FCVT_S_LU: W_FCVT_S_LU(rd, rs); break; default: assert(false); return NULL; } return code->buf; @@ -671,6 +697,10 @@ static unsigned char *asm_if(Inst *inst, Code *code) { case FCVT_WU_D: W_FCVT_WU_D(rd, rs, rm); break; case FCVT_L_D: W_FCVT_L_D(rd, rs, rm); break; case FCVT_LU_D: W_FCVT_LU_D(rd, rs, rm); break; + case FCVT_W_S: W_FCVT_W_S(rd, rs, rm); break; + case FCVT_WU_S: W_FCVT_WU_S(rd, rs, rm); break; + case FCVT_L_S: W_FCVT_L_S(rd, rs, rm); break; + case FCVT_LU_S: W_FCVT_LU_S(rd, rs, rm); break; default: assert(false); return NULL; } return code->buf; @@ -775,7 +805,9 @@ static const AsmInstTable *table[] = { [RET] = (const AsmInstTable[]){ {asm_ret, NOOPERAND, NOOPERAND, NOOPERAND}, {NULL} }, [FADD_D] = table_3fr, [FSUB_D] = table_3fr, [FMUL_D] = table_3fr, [FDIV_D] = table_3fr, + [FADD_S] = table_3fr, [FSUB_S] = table_3fr, [FMUL_S] = table_3fr, [FDIV_S] = table_3fr, [FMV_D] = table_2fr, [FNEG_D] = table_2fr, + [FMV_S] = table_2fr, [FNEG_S] = table_2fr, [FMV_X_D] = table_if, [FMV_X_W] = table_if, [FEQ_D] = table_fcmp, [FLT_D] = table_fcmp, [FLE_D] = table_fcmp, [FEQ_S] = table_fcmp, [FLT_S] = table_fcmp, [FLE_S] = table_fcmp, @@ -785,6 +817,10 @@ static const AsmInstTable *table[] = { [FCVT_D_L] = table_fi, [FCVT_D_LU] = table_fi, [FCVT_W_D] = table_if, [FCVT_WU_D] = table_if, [FCVT_L_D] = table_if, [FCVT_LU_D] = table_if, + [FCVT_S_W] = table_fi, [FCVT_S_WU] = table_fi, + [FCVT_S_L] = table_fi, [FCVT_S_LU] = table_fi, + [FCVT_W_S] = table_if, [FCVT_WU_S] = table_if, + [FCVT_L_S] = table_if, [FCVT_LU_S] = table_if, [FCVT_D_S] = table_2fr, [FCVT_S_D] = table_2fr, }; diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index 24cf579c7..dd6b11a72 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -41,7 +41,9 @@ enum Opcode { RET, FADD_D, FSUB_D, FMUL_D, FDIV_D, + FADD_S, FSUB_S, FMUL_S, FDIV_S, FMV_D, FNEG_D, + FMV_S, FNEG_S, FMV_X_D, FMV_X_W, FEQ_D, FLT_D, FLE_D, FEQ_S, FLT_S, FLE_S, @@ -49,6 +51,8 @@ enum Opcode { FCVT_D_W, FCVT_D_WU, FCVT_D_L, FCVT_D_LU, FCVT_W_D, FCVT_WU_D, FCVT_L_D, FCVT_LU_D, + FCVT_S_W, FCVT_S_WU, FCVT_S_L, FCVT_S_LU, + FCVT_W_S, FCVT_WU_S, FCVT_L_S, FCVT_LU_S, FCVT_D_S, FCVT_S_D, }; diff --git a/src/as/arch/riscv64/parse_riscv64.c b/src/as/arch/riscv64/parse_riscv64.c index 394e7266d..a23089d3e 100644 --- a/src/as/arch/riscv64/parse_riscv64.c +++ b/src/as/arch/riscv64/parse_riscv64.c @@ -43,13 +43,17 @@ static const char *kOpTable[] = { "ret", "fadd.d", "fsub.d", "fmul.d", "fdiv.d", + "fadd.s", "fsub.s", "fmul.s", "fdiv.s", "fmv.d", "fneg.d", + "fmv.s", "fneg.s", "fmv.x.d", "fmv.x.w", "feq.d", "flt.d", "fle.d", "feq.s", "flt.s", "fle.s", "fld", "flw", "fsd", "fsw", "fcvt.d.w", "fcvt.d.wu", "fcvt.d.l", "fcvt.d.lu", "fcvt.w.d", "fcvt.wu.d", "fcvt.l.d", "fcvt.lu.d", + "fcvt.s.w", "fcvt.s.wu", "fcvt.s.l", "fcvt.s.lu", + "fcvt.w.s", "fcvt.wu.s", "fcvt.l.s", "fcvt.lu.s", "fcvt.d.s", "fcvt.s.d", }; From b3e4d257d4319b6e9e7af75f220f578bdb3fad3b Mon Sep 17 00:00:00 2001 From: tyfkda Date: Tue, 23 Apr 2024 22:33:32 +0900 Subject: [PATCH 21/25] Avoid name conflict with register name TODO: Fix operand parser. --- tests/valtest.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/valtest.c b/tests/valtest.c index 727f59655..4203bd3b9 100644 --- a/tests/valtest.c +++ b/tests/valtest.c @@ -904,8 +904,8 @@ long proto_in_func(short x) { return x + 1; } typedef int SameTypedefAllowed; typedef int SameTypedefAllowed; -int f27(void){return 27;} -int f53(void){return 53;} +int fc27(void){return 27;} +int fc53(void){return 53;} void mul2p(int *p) {*p *= 2;} const char *retstr(void){ return "foo"; } @@ -1158,7 +1158,7 @@ TTT:; EXPECT("ternary ptr:0", 98, *q); int selector = 0; - EXPECT("ternary w/ func", 53, (selector ? f27 : f53)()); + EXPECT("ternary w/ func", 53, (selector ? fc27 : fc53)()); char buf[16] = ""; selector ? (void)strcpy(buf, "true") : (void)strcpy(buf, "false"); From 1761a50a38042270ad0831f4f5931a44b99e64a9 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Wed, 24 Apr 2024 15:01:20 +0900 Subject: [PATCH 22/25] Use own assembler on RISC-V Continue using system linker, though. --- src/config.h | 5 +++-- src/xcc/main.c | 20 ++++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/config.h b/src/config.h index 2bb90e875..09967f9e9 100644 --- a/src/config.h +++ b/src/config.h @@ -38,13 +38,14 @@ // #if XCC_TARGET_ARCH == XCC_ARCH_AARCH64 -# define AS_USE_CC +# define USE_SYS_AS +# define USE_SYS_LD # if XCC_TARGET_PLATFORM != XCC_PLATFORM_APPLE # define NO_STD_LIB # endif #elif XCC_TARGET_ARCH != XCC_ARCH_X64 && XCC_TARGET_ARCH != XCC_ARCH_WASM -# define AS_USE_CC +# define USE_SYS_LD #endif #define USE_ALLOCA diff --git a/src/xcc/main.c b/src/xcc/main.c index 2a45b8217..01d61e1e2 100644 --- a/src/xcc/main.c +++ b/src/xcc/main.c @@ -549,20 +549,24 @@ int main(int argc, char *argv[]) { const char *prefix = get_exe_prefix(xccpath); char *cpp_path = join_exe_prefix(xccpath, prefix, "cpp"); char *cc1_path = join_exe_prefix(xccpath, prefix, "cc1"); -#if !defined(AS_USE_CC) - char *as_path = join_exe_prefix(xccpath, prefix, "as"); - char *ld_path = join_exe_prefix(xccpath, prefix, "ld"); -#elif defined(HOST_CC_PREFIX) #define S(x) S2(x) #define S2(x) #x +#if !defined(USE_SYS_AS) + char *as_path = join_exe_prefix(xccpath, prefix, "as"); +#elif defined(HOST_CC_PREFIX) char *as_path = S(HOST_CC_PREFIX) "as"; - char *ld_path = S(HOST_CC_PREFIX) "gcc"; -#undef S2 -#undef S #else char *as_path = "/usr/bin/as"; +#endif +#if !defined(USE_SYS_LD) + char *ld_path = join_exe_prefix(xccpath, prefix, "ld"); +#elif defined(HOST_CC_PREFIX) + char *ld_path = S(HOST_CC_PREFIX) "gcc"; +#else char *ld_path = "/usr/bin/cc"; #endif +#undef S2 +#undef S Vector *cpp_cmd = new_vector(); vec_push(cpp_cmd, cpp_path); @@ -635,7 +639,7 @@ int main(int argc, char *argv[]) { } if (opts.out_type >= OutExecutable && !opts.use_ld) { -#if !defined(AS_USE_CC) || defined(NO_STD_LIB) +#if !defined(USE_SYS_LD) || defined(NO_STD_LIB) if (!opts.nostdlib) vec_push(opts.sources, JOIN_PATHS(root, "lib/crt0.a")); if (!opts.nodefaultlibs && !opts.nostdlib) From cee6ae61130ced9764f4963c50524fb836f105c1 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Wed, 24 Apr 2024 19:18:47 +0900 Subject: [PATCH 23/25] Put offset in branch instruction Just in case. --- src/as/arch/riscv64/ir_asm.c | 41 ++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/src/as/arch/riscv64/ir_asm.c b/src/as/arch/riscv64/ir_asm.c index 0989f6c2f..1058fd62c 100644 --- a/src/as/arch/riscv64/ir_asm.c +++ b/src/as/arch/riscv64/ir_asm.c @@ -215,6 +215,7 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * break; case J: if (inst->opr1.type == DIRECT) { + int64_t target_address = 0; Value value = calc_expr(label_table, inst->opr1.direct.expr); if (value.label != NULL) { // Put rela even if the label is defined in the same object file. @@ -226,17 +227,35 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * info->offset = address - start_address; info->add = value.offset; vec_push(unresolved, info); - break; + + LabelInfo *label_info = table_get(label_table, value.label); + if (label_info != NULL) + target_address = label_info->address + value.offset; + } + + if (target_address != 0) { + Code *code = &ir->code; + int64_t offset = target_address - VOIDP2INT(address); + if (offset < (1 << 11) && offset >= -(1 << 11)) { + assert(code->len == 2); + uint16_t *buf = (uint16_t*)code->buf; + // Compressed: imm[11|4|9:8|10|6|7|3:1|5] +#define IMM(imm, t, b) (((imm) >> (b)) & ((1 << (t - b + 1)) - 1)) + buf[0] = (buf[0] & 0xe003) | (IMM(offset, 11, 11) << 12) | (IMM(offset, 4, 4) << 11) | + (IMM(offset, 9, 8) << 9) | (IMM(offset, 10, 10) << 8) | (IMM(offset, 6, 6) << 7) | + (IMM(offset, 7, 7) << 6) | (IMM(offset, 3, 1) << 3) | (IMM(offset, 5, 5) << 2); + } } } break; case BEQ: case BNE: case BLT: case BGE: case BLTU: case BGEU: if (inst->opr3.type == DIRECT) { + bool comp = inst->opr2.reg.no == 0 && is_rvc_reg(inst->opr1.reg.no) && + (inst->op == BEQ || inst->op == BNE); + int64_t target_address = 0; Value value = calc_expr(label_table, inst->opr3.direct.expr); if (value.label != NULL) { assert(inst->opr2.type == REG); - bool comp = inst->opr2.reg.no == 0 && is_rvc_reg(inst->opr1.reg.no) && - (inst->op == BEQ || inst->op == BNE); // Put rela even if the label is defined in the same object file. UnresolvedInfo *info; info = calloc_or_die(sizeof(*info)); @@ -246,7 +265,21 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * info->offset = address - start_address; info->add = value.offset; vec_push(unresolved, info); - break; + + LabelInfo *label_info = table_get(label_table, value.label); + if (label_info != NULL) + target_address = label_info->address + value.offset; + } + + if (!comp && target_address != 0) { + Code *code = &ir->code; + int64_t offset = target_address - VOIDP2INT(address); + if (offset < (1 << 11) && offset >= -(1 << 11)) { + assert(code->len == 4); + uint32_t *buf = (uint32_t*)code->buf; + // STYPE + buf[0] = (buf[0] & 0x01fff07f) | (IMM(offset, 11, 5) << 25) | (IMM(offset, 4, 0) << 7); + } } } break; From 0f62ca9c5102cf2a14dc93fadf52e5f0b6913784 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Thu, 25 Apr 2024 12:28:56 +0900 Subject: [PATCH 24/25] Extend compressed to normal instruction if needed `c.j` => `j`. --- src/as/arch/riscv64/asm_code.c | 1 - src/as/arch/riscv64/ir_asm.c | 58 +++++++++++++++++++++++++++++----- src/as/as.c | 3 +- src/as/ir_asm.h | 1 + src/util/gen_section.c | 2 +- 5 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index fa4a52f2c..2bb5f4629 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -499,7 +499,6 @@ static unsigned char *asm_sd(Inst *inst, Code *code) { static unsigned char *asm_j(Inst *inst, Code *code) { UNUSED(inst); - // TODO: Non compact instruction? // imm[11|4|9:8|10|6|7|3:1|5] C_J(); return code->buf; diff --git a/src/as/arch/riscv64/ir_asm.c b/src/as/arch/riscv64/ir_asm.c index 1058fd62c..f8795234e 100644 --- a/src/as/arch/riscv64/ir_asm.c +++ b/src/as/arch/riscv64/ir_asm.c @@ -153,6 +153,31 @@ bool calc_label_address(uintptr_t start_address, Vector **section_irs, Table *la return settle; } +#ifndef MAKE_CODE32 +#define MAKE_CODE32(inst, code, ...) do { unsigned int buf[] = {__VA_ARGS__}; make_code32(inst, code, buf, sizeof(buf)); } while (0) +#endif +void make_code32(Inst *inst, Code *code, unsigned int *buf, int len); + +#define ZERO 0 +#define IMM(imm, t, b) (((imm) >> (b)) & ((1 << (t - b + 1)) - 1)) +#define UTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 31, 12) << 12) | ((rd) << 7) | (opcode)) // U-type +#define W_JAL(rd, imm) UTYPE(imm, rd, 0x6f) + +static bool make_jmp_long(IR *ir) { + if (ir->code.flag & INST_LONG_OFFSET) + return false; + + Code *code = &ir->code; + Inst *inst = code->inst; + // Change to long offset, and recalculate. + code->flag |= INST_LONG_OFFSET; + code->len = 0; + assert(inst->op == J); + + W_JAL(ZERO, 0); + return true; +} + bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector *unresolved) { assert(unresolved != NULL); vec_clear(unresolved); @@ -221,7 +246,7 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * // Put rela even if the label is defined in the same object file. UnresolvedInfo *info; info = calloc_or_die(sizeof(*info)); - info->kind = UNRES_RISCV_RVC_JUMP; + info->kind = (ir->code.flag & INST_LONG_OFFSET) ? UNRES_RISCV_JAL : UNRES_RISCV_RVC_JUMP; info->label = value.label; info->src_section = sec; info->offset = address - start_address; @@ -236,14 +261,28 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * if (target_address != 0) { Code *code = &ir->code; int64_t offset = target_address - VOIDP2INT(address); - if (offset < (1 << 11) && offset >= -(1 << 11)) { + bool long_offset = ir->code.flag & INST_LONG_OFFSET; + if (!long_offset) { assert(code->len == 2); - uint16_t *buf = (uint16_t*)code->buf; - // Compressed: imm[11|4|9:8|10|6|7|3:1|5] -#define IMM(imm, t, b) (((imm) >> (b)) & ((1 << (t - b + 1)) - 1)) - buf[0] = (buf[0] & 0xe003) | (IMM(offset, 11, 11) << 12) | (IMM(offset, 4, 4) << 11) | - (IMM(offset, 9, 8) << 9) | (IMM(offset, 10, 10) << 8) | (IMM(offset, 6, 6) << 7) | - (IMM(offset, 7, 7) << 6) | (IMM(offset, 3, 1) << 3) | (IMM(offset, 5, 5) << 2); + if (offset < (1 << 11) && offset >= -(1 << 11)) { + uint16_t *buf = (uint16_t*)code->buf; + // Compressed: imm[11|4|9:8|10|6|7|3:1|5] + buf[0] = (buf[0] & 0xe003) | (IMM(offset, 11, 11) << 12) | (IMM(offset, 4, 4) << 11) | + (IMM(offset, 9, 8) << 9) | (IMM(offset, 10, 10) << 8) | (IMM(offset, 6, 6) << 7) | + (IMM(offset, 7, 7) << 6) | (IMM(offset, 3, 1) << 3) | (IMM(offset, 5, 5) << 2); + } else { + size_upgraded |= make_jmp_long(ir); + } + } else { + if (offset < (1 << 20) && offset >= -(1 << 20)) { + uint32_t *buf = (uint32_t*)code->buf; + // Compressed: imm[20|10:1|11|19:12] + buf[0] = (buf[0] & 0x000007ff) | (IMM(offset, 20, 20) << 31) | (IMM(offset, 10, 1) << 21) | + (IMM(offset, 11, 11) << 20) | (IMM(offset, 19, 12) << 12); + } else { + // Linker extends the branch instruction to long offset? + assert(false); + } } } } @@ -279,6 +318,9 @@ bool resolve_relative_address(Vector **section_irs, Table *label_table, Vector * uint32_t *buf = (uint32_t*)code->buf; // STYPE buf[0] = (buf[0] & 0x01fff07f) | (IMM(offset, 11, 5) << 25) | (IMM(offset, 4, 0) << 7); + } else { + // Linker extends the branch instruction to long offset? + // assert(false); } } } diff --git a/src/as/as.c b/src/as/as.c index 8c5652115..748cc27ae 100644 --- a/src/as/as.c +++ b/src/as/as.c @@ -292,13 +292,14 @@ static int output_obj(const char *ofn, Table *label_table, Vector *unresolved) { rela->r_addend = u->add; } break; + case UNRES_RISCV_JAL: case UNRES_RISCV_RVC_JUMP: { int symidx = symtab_find(&symtab, u->label); assert(symidx >= 0); rela->r_offset = u->offset; - rela->r_info = ELF64_R_INFO(symidx, R_RISCV_RVC_JUMP); + rela->r_info = ELF64_R_INFO(symidx, u->kind == UNRES_RISCV_JAL ? R_RISCV_JAL : R_RISCV_RVC_JUMP); rela->r_addend = u->add; } break; diff --git a/src/as/ir_asm.h b/src/as/ir_asm.h index ad252ac11..d4aec40da 100644 --- a/src/as/ir_asm.h +++ b/src/as/ir_asm.h @@ -38,6 +38,7 @@ enum UnresolvedKind { UNRES_ABS64, UNRES_RISCV_BRANCH, + UNRES_RISCV_JAL, UNRES_RISCV_CALL, UNRES_RISCV_PCREL_HI20, UNRES_RISCV_PCREL_LO12_I, diff --git a/src/util/gen_section.c b/src/util/gen_section.c index 1596e60e4..e0f03a610 100644 --- a/src/util/gen_section.c +++ b/src/util/gen_section.c @@ -15,7 +15,7 @@ typedef struct { static Section sections[SECTION_COUNT]; static size_t bss_size; -size_t section_aligns[SECTION_COUNT] = {1, 1, 1, 1}; +size_t section_aligns[SECTION_COUNT] = {8, 8, 1, 1}; uintptr_t section_start_addresses[SECTION_COUNT]; void add_bss(size_t size) { From 37fd02e7354e0e4f145a2e152c799af07a47c122 Mon Sep 17 00:00:00 2001 From: tyfkda Date: Fri, 26 Apr 2024 08:15:29 +0900 Subject: [PATCH 25/25] Separate code macro --- src/as/arch/aarch64/asm_code.c | 8 -- src/as/arch/riscv64/asm_code.c | 171 +--------------------------- src/as/arch/riscv64/inst.h | 5 - src/as/arch/riscv64/ir_asm.c | 11 +- src/as/arch/riscv64/riscv64_code.h | 176 +++++++++++++++++++++++++++++ src/as/asm_code.h | 10 ++ 6 files changed, 188 insertions(+), 193 deletions(-) create mode 100644 src/as/arch/riscv64/riscv64_code.h diff --git a/src/as/arch/aarch64/asm_code.c b/src/as/arch/aarch64/asm_code.c index 5b3bf9f28..1743aa97a 100644 --- a/src/as/arch/aarch64/asm_code.c +++ b/src/as/arch/aarch64/asm_code.c @@ -8,14 +8,6 @@ #include "parse_asm.h" #include "util.h" -#ifndef MAKE_CODE16 -#define MAKE_CODE16(inst, code, ...) do { unsigned short buf[] = {__VA_ARGS__}; make_code16(inst, code, buf, sizeof(buf)); } while (0) -#endif - -#ifndef MAKE_CODE32 -#define MAKE_CODE32(inst, code, ...) do { unsigned int buf[] = {__VA_ARGS__}; make_code32(inst, code, buf, sizeof(buf)); } while (0) -#endif - void make_code16(Inst *inst, Code *code, unsigned short *buf, int len) { assert(code->len + len <= (int)sizeof(code->buf)); code->inst = inst; diff --git a/src/as/arch/riscv64/asm_code.c b/src/as/arch/riscv64/asm_code.c index 2bb5f4629..41249b2d6 100644 --- a/src/as/arch/riscv64/asm_code.c +++ b/src/as/arch/riscv64/asm_code.c @@ -6,16 +6,9 @@ #include "inst.h" #include "parse_asm.h" +#include "riscv64_code.h" #include "util.h" -#ifndef MAKE_CODE16 -#define MAKE_CODE16(inst, code, ...) do { unsigned short buf[] = {__VA_ARGS__}; make_code16(inst, code, buf, sizeof(buf)); } while (0) -#endif - -#ifndef MAKE_CODE32 -#define MAKE_CODE32(inst, code, ...) do { unsigned int buf[] = {__VA_ARGS__}; make_code32(inst, code, buf, sizeof(buf)); } while (0) -#endif - void make_code16(Inst *inst, Code *code, unsigned short *buf, int len) { assert(code->len + len <= (int)sizeof(code->buf)); code->inst = inst; @@ -45,168 +38,6 @@ inline bool assemble_error(const ParseInfo *info, const char *message) { // -#define ZERO 0 -#define RA 1 -#define SP 2 - -#define IMM(imm, t, b) (((imm) >> (b)) & ((1 << (t - b + 1)) - 1)) -#define RTYPE(funct7, rs2, rs1, funct3, rd, opcode) MAKE_CODE32(inst, code, ((funct7) << 25) | ((rs2) << 20) | ((rs1) << 15) | ((funct3) << 12) | ((rd) << 7) | (opcode)) // R-type -#define ITYPE(imm, rs1, funct3, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 11, 0) << 20) | ((rs1) << 15) | ((funct3) << 12) | ((rd) << 7) | (opcode)) // I-type -#define STYPE(imm, rs2, rs1, funct3, opcode) MAKE_CODE32(inst, code, (IMM(imm, 11, 5) << 25) | ((rs2) << 20) | ((rs1) << 15) | ((funct3) << 12) | (IMM(imm, 4, 0) << 7) | (opcode)) // S-type -#define BTYPE(imm, rs2, rs1, funct3, opcode) MAKE_CODE32(inst, code, (IMM(imm, 12, 12) << 31) | (IMM(imm, 10, 5) << 25) | ((rs2) << 20) | ((rs1) << 15) | ((funct3) << 12) | (IMM(imm, 4, 0) << 7) | (opcode)) // B-type -#define UTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 31, 12) << 12) | ((rd) << 7) | (opcode)) // U-type -#define JTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 20, 20) << 31) | (IMM(imm, 10, 1) << 20) | (IMM(imm, 11, 11) << 19) | (IMM(imm, 19, 12) << 12) | ((rd) << 7) | (opcode)) // J-type - -#define W_ADD(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x00, rd, 0x33) -#define W_ADDW(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x00, rd, 0x3b) -#define W_ADDI(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x13) -#define W_ADDIW(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x1b) -#define W_SUB(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x00, rd, 0x33) -#define W_SUBW(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x00, rd, 0x3b) -#define W_MUL(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x00, rd, 0x33) -#define W_MULW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x00, rd, 0x3b) -#define W_DIV(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x04, rd, 0x33) -#define W_DIVU(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x05, rd, 0x33) -#define W_DIVW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x04, rd, 0x3b) -#define W_DIVUW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x05, rd, 0x3b) -#define W_REM(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x06, rd, 0x33) -#define W_REMU(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x33) -#define W_REMW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x06, rd, 0x3b) -#define W_REMUW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x3b) -#define W_AND(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x07, rd, 0x33) -#define W_ANDI(rd, rs, imm) ITYPE(imm, rs, 0x07, rd, 0x13) -#define W_OR(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x06, rd, 0x33) -#define W_ORI(rd, rs, imm) ITYPE(imm, rs, 0x06, rd, 0x13) -#define W_XOR(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x04, rd, 0x33) -#define W_XORI(rd, rs, imm) ITYPE(imm, rs, 0x04, rd, 0x13) -#define W_SLL(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x01, rd, 0x33) -#define W_SLLI(rd, rs, imm) ITYPE((imm) & 63, rs, 0x01, rd, 0x13) -#define W_SLLIW(rd, rs, imm) ITYPE((imm) & 31, rs, 0x01, rd, 0x1b) -#define W_SRL(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x05, rd, 0x33) -#define W_SRLI(rd, rs, imm) ITYPE((imm) & 63, rs, 0x05, rd, 0x13) -#define W_SRA(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x05, rd, 0x33) -#define W_SRAI(rd, rs, imm) ITYPE(0x400 | ((imm) & 63), rs, 0x05, rd, 0x13) -#define W_SLT(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x02, rd, 0x33) -#define W_SLTU(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x03, rd, 0x33) -#define W_SLTI(rd, rs, imm) ITYPE(imm, rs, 0x02, rd, 0x13) -#define W_SLTIU(rd, rs, imm) ITYPE(imm, rs, 0x03, rd, 0x13) -#define W_LB(rd, ofs, rs) ITYPE(ofs, rs, 0x00, rd, 0x03) -#define W_LH(rd, ofs, rs) ITYPE(ofs, rs, 0x01, rd, 0x03) -#define W_LW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x03) -#define W_LD(rd, ofs, rs) ITYPE(ofs, rs, 0x03, rd, 0x03) -#define W_LBU(rd, ofs, rs) ITYPE(ofs, rs, 0x04, rd, 0x03) -#define W_LHU(rd, ofs, rs) ITYPE(ofs, rs, 0x05, rd, 0x03) -#define W_LWU(rd, ofs, rs) ITYPE(ofs, rs, 0x06, rd, 0x03) -#define W_SB(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x00, 0x23) -#define W_SH(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x01, 0x23) -#define W_SW(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x02, 0x23) -#define W_SD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x23) -#define W_LUI(rd, imm) UTYPE(imm, rd, 0x37) -#define W_AUIPC(rd, imm) UTYPE(imm, rd, 0x17) -#define W_JALR(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x67) -#define W_BXX(funct3, rs1, rs2, ofs) STYPE(ofs, rs2, rs1, funct3, 0x63) - -#define W_FADD_D(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x53) -#define W_FSUB_D(rd, rs1, rs2) RTYPE(0x05, rs2, rs1, 0x07, rd, 0x53) -#define W_FMUL_D(rd, rs1, rs2) RTYPE(0x09, rs2, rs1, 0x07, rd, 0x53) -#define W_FDIV_D(rd, rs1, rs2) RTYPE(0x0d, rs2, rs1, 0x07, rd, 0x53) -#define W_FADD_S(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x07, rd, 0x53) -#define W_FSUB_S(rd, rs1, rs2) RTYPE(0x04, rs2, rs1, 0x07, rd, 0x53) -#define W_FMUL_S(rd, rs1, rs2) RTYPE(0x08, rs2, rs1, 0x07, rd, 0x53) -#define W_FDIV_S(rd, rs1, rs2) RTYPE(0x0c, rs2, rs1, 0x07, rd, 0x53) -#define W_FEQ_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x02, rd, 0x53) -#define W_FLT_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x01, rd, 0x53) -#define W_FLE_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x00, rd, 0x53) -#define W_FEQ_S(rd, rs1, rs2) RTYPE(0x50, rs2, rs1, 0x02, rd, 0x53) -#define W_FLT_S(rd, rs1, rs2) RTYPE(0x50, rs2, rs1, 0x01, rd, 0x53) -#define W_FLE_S(rd, rs1, rs2) RTYPE(0x50, rs2, rs1, 0x00, rd, 0x53) -#define W_FLD(rd, ofs, rs) ITYPE(ofs, rs, 0x03, rd, 0x07) -#define W_FLW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x07) -#define W_FSD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x27) -#define W_FSW(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x02, 0x27) -#define W_FSGNJ_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x00, rd, 0x53) -#define W_FSGNJ_S(rd, rs1, rs2) RTYPE(0x10, rs2, rs1, 0x00, rd, 0x53) -#define W_FSGNJN_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x01, rd, 0x53) -#define W_FSGNJN_S(rd, rs1, rs2) RTYPE(0x10, rs2, rs1, 0x01, rd, 0x53) - -#define W_FCVT_D_W(rd, rs) RTYPE(0x69, 0, rs, 0x00, rd, 0x53) -#define W_FCVT_D_WU(rd, rs) RTYPE(0x69, 1, rs, 0x00, rd, 0x53) -#define W_FCVT_D_L(rd, rs) RTYPE(0x69, 2, rs, 0x07, rd, 0x53) -#define W_FCVT_D_LU(rd, rs) RTYPE(0x69, 3, rs, 0x07, rd, 0x53) -#define W_FCVT_S_W(rd, rs) RTYPE(0x68, 0, rs, 0x07, rd, 0x53) -#define W_FCVT_S_WU(rd, rs) RTYPE(0x68, 1, rs, 0x07, rd, 0x53) -#define W_FCVT_S_L(rd, rs) RTYPE(0x68, 2, rs, 0x07, rd, 0x53) -#define W_FCVT_S_LU(rd, rs) RTYPE(0x68, 3, rs, 0x07, rd, 0x53) - -#define W_FCVT_W_D(rd, rs, rm) RTYPE(0x61, 0, rs, rm, rd, 0x53) -#define W_FCVT_WU_D(rd, rs, rm) RTYPE(0x61, 1, rs, rm, rd, 0x53) -#define W_FCVT_L_D(rd, rs, rm) RTYPE(0x61, 2, rs, rm, rd, 0x53) -#define W_FCVT_LU_D(rd, rs, rm) RTYPE(0x61, 3, rs, rm, rd, 0x53) -#define W_FCVT_W_S(rd, rs, rm) RTYPE(0x60, 0, rs, rm, rd, 0x53) -#define W_FCVT_WU_S(rd, rs, rm) RTYPE(0x60, 1, rs, rm, rd, 0x53) -#define W_FCVT_L_S(rd, rs, rm) RTYPE(0x60, 2, rs, rm, rd, 0x53) -#define W_FCVT_LU_S(rd, rs, rm) RTYPE(0x60, 3, rs, rm, rd, 0x53) - -#define W_FCVT_D_S(rd, rs) RTYPE(0x21, 0, rs, 0x00, rd, 0x53) -#define W_FCVT_S_D(rd, rs) RTYPE(0x20, 1, rs, 0x07, rd, 0x53) - -#define W_FMV_X_D(rd, rs) RTYPE(0x71, 0, rs, 0x00, rd, 0x53) -#define W_FMV_X_W(rd, rs) RTYPE(0x70, 0, rs, 0x00, rd, 0x53) - -#define C_MV(rd, rs) MAKE_CODE16(inst, code, 0x8002 | ((rd) << 7) | ((rs) << 2)) -#define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 17, 17) << 12) | ((rd) << 7) | (IMM(imm, 16, 12) << 2)) -#define C_ADD(rd, rs) MAKE_CODE16(inst, code, 0x9002 | ((rd) << 7) | ((rs) << 2)) -#define C_ADDW(rd, rs) MAKE_CODE16(inst, code, 0x9c21 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) -#define C_ADDI(rd, imm) MAKE_CODE16(inst, code, 0x0001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_ADDIW(rd, imm) MAKE_CODE16(inst, code, 0x2001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_ADDI16SP(imm) MAKE_CODE16(inst, code, 0x6101 | (IMM(imm, 9, 9) << 12) | (IMM(imm, 4, 4) << 6) | (IMM(imm, 6, 6) << 5) | (IMM(imm, 8, 7) << 3) | (IMM(imm, 5, 5) << 2)) -#define C_SUB(rd, rs) MAKE_CODE16(inst, code, 0x8c01 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) -#define C_SUBW(rd, rs) MAKE_CODE16(inst, code, 0x9c01 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) -#define C_AND(rd, rs) MAKE_CODE16(inst, code, 0x8c61 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) -#define C_ANDI(rd, imm) MAKE_CODE16(inst, code, 0x8801 | (IMM(imm, 5, 5) << 12) | (to_rvc_reg(rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_OR(rd, rs) MAKE_CODE16(inst, code, 0x8c41 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) -#define C_XOR(rd, rs) MAKE_CODE16(inst, code, 0x8c21 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) -#define C_SLLI(rd, imm) MAKE_CODE16(inst, code, 0x0002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_SRLI(rd, imm) MAKE_CODE16(inst, code, 0x8001 | (IMM(imm, 5, 5) << 12) | (to_rvc_reg(rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_SRAI(rd, imm) MAKE_CODE16(inst, code, 0x8401 | (IMM(imm, 5, 5) << 12) | (to_rvc_reg(rd) << 7) | (IMM(imm, 4, 0) << 2)) -#define C_LW(rd, imm, rs) MAKE_CODE16(inst, code, 0x4000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 2, 2) << 6) | (IMM(imm, 6, 6) << 5) | (to_rvc_reg(rd) << 2)) -#define C_LD(rd, imm, rs) MAKE_CODE16(inst, code, 0x6000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rd) << 2)) -#define C_SW(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xc000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rs2) << 2)) -#define C_SD(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xe000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rs2) << 2)) -#define C_LDSP(rd, imm) MAKE_CODE16(inst, code, 0x6002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) -#define C_SDSP(rs, imm) MAKE_CODE16(inst, code, 0xe002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) -#define C_J() MAKE_CODE16(inst, code, 0xa001) -#define C_JR(rs) MAKE_CODE16(inst, code, 0x8002 | ((rs) << 7)) -#define C_JALR(rs) MAKE_CODE16(inst, code, 0x9002 | ((rs) << 7)) -#define C_BEQZ(rs) MAKE_CODE16(inst, code, 0xc001 | (to_rvc_reg(rs) << 7)) -#define C_BNEZ(rs) MAKE_CODE16(inst, code, 0xe001 | (to_rvc_reg(rs) << 7)) - -#define C_FLD(rd, imm, rs) MAKE_CODE16(inst, code, 0x2000 | (IMM(imm, 5, 3) << 10) | (to_rvc_freg(rs) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_freg(rd) << 2)) -#define C_FSD(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xa000 | (IMM(imm, 5, 3) << 10) | (to_rvc_freg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_freg(rs2) << 2)) -#define C_FLDSP(rd, imm) MAKE_CODE16(inst, code, 0x2002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) -#define C_FSDSP(rs, imm) MAKE_CODE16(inst, code, 0xa002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) - -#define P_RET() C_JR(RA) -#define P_LI(rd, imm) W_ADDI(rd, ZERO, imm) -#define P_NEG(rd, rs) W_SUB(rd, ZERO, rs) -#define P_NOT(rd, rs) W_XORI(rd, rs, -1) -#define P_SEXT_B(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 56); else W_SLLI(rd, rs, 56); C_SRAI(rd, 56); } while (0) -#define P_SEXT_H(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 48); else W_SLLI(rd, rs, 48); C_SRAI(rd, 48); } while (0) -#define P_SEXT_W(rd, rs) do { if ((rd) == (rs)) C_ADDIW(rd, 0); else W_ADDIW(rd, rs, 0); } while (0) -#define P_ZEXT_B(rd, rs) W_ANDI(rd, rs, 0xff) -#define P_ZEXT_H(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 48); else W_SLLI(rd, rs, 48); C_SRLI(rd, 48); } while (0) -#define P_ZEXT_W(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 32); else W_SLLI(rd, rs, 32); C_SRLI(rd, 32); } while (0) -#define P_SEQZ(rd, rs) W_SLTIU(rd, rs, 1) -#define P_SNEZ(rd, rs) W_SLTU(rd, ZERO, rs) -#define P_SLTZ(rd, rs) W_SLT(rd, rs, ZERO) -#define P_SGTZ(rd, rs) W_SLT(rd, ZERO, rs) - -#define P_FMV_D(rd, rs) W_FSGNJ_D(rd, rs, rs) -#define P_FMV_S(rd, rs) W_FSGNJ_S(rd, rs, rs) -#define P_FNEG_D(rd, rs) W_FSGNJN_D(rd, rs, rs) -#define P_FNEG_S(rd, rs) W_FSGNJN_S(rd, rs, rs) - extern inline bool is_rvc_reg(int reg); extern inline int to_rvc_reg(int reg); diff --git a/src/as/arch/riscv64/inst.h b/src/as/arch/riscv64/inst.h index dd6b11a72..70c1ac1f8 100644 --- a/src/as/arch/riscv64/inst.h +++ b/src/as/arch/riscv64/inst.h @@ -114,8 +114,3 @@ typedef struct Inst { Operand opr2; Operand opr3; } Inst; - -inline bool is_rvc_reg(int reg) { return reg >= 8 && reg <= 15; } // X8~X15 -inline int to_rvc_reg(int reg) { return reg - 8; } -#define is_rvc_freg is_rvc_reg -#define to_rvc_freg to_rvc_reg diff --git a/src/as/arch/riscv64/ir_asm.c b/src/as/arch/riscv64/ir_asm.c index f8795234e..2a9437e7a 100644 --- a/src/as/arch/riscv64/ir_asm.c +++ b/src/as/arch/riscv64/ir_asm.c @@ -7,6 +7,7 @@ #include "gen_section.h" #include "inst.h" #include "parse_asm.h" +#include "riscv64_code.h" #include "table.h" #include "util.h" @@ -153,16 +154,6 @@ bool calc_label_address(uintptr_t start_address, Vector **section_irs, Table *la return settle; } -#ifndef MAKE_CODE32 -#define MAKE_CODE32(inst, code, ...) do { unsigned int buf[] = {__VA_ARGS__}; make_code32(inst, code, buf, sizeof(buf)); } while (0) -#endif -void make_code32(Inst *inst, Code *code, unsigned int *buf, int len); - -#define ZERO 0 -#define IMM(imm, t, b) (((imm) >> (b)) & ((1 << (t - b + 1)) - 1)) -#define UTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 31, 12) << 12) | ((rd) << 7) | (opcode)) // U-type -#define W_JAL(rd, imm) UTYPE(imm, rd, 0x6f) - static bool make_jmp_long(IR *ir) { if (ir->code.flag & INST_LONG_OFFSET) return false; diff --git a/src/as/arch/riscv64/riscv64_code.h b/src/as/arch/riscv64/riscv64_code.h new file mode 100644 index 000000000..eccc3ed04 --- /dev/null +++ b/src/as/arch/riscv64/riscv64_code.h @@ -0,0 +1,176 @@ +// riscv64 Code macros + +#pragma once + +#define ZERO 0 +#define RA 1 +#define SP 2 + +#define IMM(imm, t, b) (((imm) >> (b)) & ((1 << (t - b + 1)) - 1)) + +// Instruction formats: 32bit=[7|5|5|3|5|7] +#define RTYPE(funct7, rs2, rs1, funct3, rd, opcode) MAKE_CODE32(inst, code, ((funct7) << 25) | ((rs2) << 20) | ((rs1) << 15) | ((funct3) << 12) | ((rd) << 7) | (opcode)) +#define ITYPE(imm, rs1, funct3, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 11, 0) << 20) | ((rs1) << 15) | ((funct3) << 12) | ((rd) << 7) | (opcode)) +#define STYPE(imm, rs2, rs1, funct3, opcode) MAKE_CODE32(inst, code, (IMM(imm, 11, 5) << 25) | ((rs2) << 20) | ((rs1) << 15) | ((funct3) << 12) | (IMM(imm, 4, 0) << 7) | (opcode)) +#define BTYPE(imm, rs2, rs1, funct3, opcode) MAKE_CODE32(inst, code, (IMM(imm, 12, 12) << 31) | (IMM(imm, 10, 5) << 25) | ((rs2) << 20) | ((rs1) << 15) | ((funct3) << 12) | (IMM(imm, 4, 0) << 7) | (opcode)) +#define UTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 31, 12) << 12) | ((rd) << 7) | (opcode)) +#define JTYPE(imm, rd, opcode) MAKE_CODE32(inst, code, (IMM(imm, 20, 20) << 31) | (IMM(imm, 10, 1) << 20) | (IMM(imm, 11, 11) << 19) | (IMM(imm, 19, 12) << 12) | ((rd) << 7) | (opcode)) + +// 32-bit instructions +#define W_ADD(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x00, rd, 0x33) +#define W_ADDW(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x00, rd, 0x3b) +#define W_ADDI(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x13) +#define W_ADDIW(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x1b) +#define W_SUB(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x00, rd, 0x33) +#define W_SUBW(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x00, rd, 0x3b) +#define W_MUL(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x00, rd, 0x33) +#define W_MULW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x00, rd, 0x3b) +#define W_DIV(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x04, rd, 0x33) +#define W_DIVU(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x05, rd, 0x33) +#define W_DIVW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x04, rd, 0x3b) +#define W_DIVUW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x05, rd, 0x3b) +#define W_REM(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x06, rd, 0x33) +#define W_REMU(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x33) +#define W_REMW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x06, rd, 0x3b) +#define W_REMUW(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x3b) +#define W_AND(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x07, rd, 0x33) +#define W_ANDI(rd, rs, imm) ITYPE(imm, rs, 0x07, rd, 0x13) +#define W_OR(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x06, rd, 0x33) +#define W_ORI(rd, rs, imm) ITYPE(imm, rs, 0x06, rd, 0x13) +#define W_XOR(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x04, rd, 0x33) +#define W_XORI(rd, rs, imm) ITYPE(imm, rs, 0x04, rd, 0x13) +#define W_SLL(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x01, rd, 0x33) +#define W_SLLI(rd, rs, imm) ITYPE((imm) & 63, rs, 0x01, rd, 0x13) +#define W_SLLIW(rd, rs, imm) ITYPE((imm) & 31, rs, 0x01, rd, 0x1b) +#define W_SRL(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x05, rd, 0x33) +#define W_SRLI(rd, rs, imm) ITYPE((imm) & 63, rs, 0x05, rd, 0x13) +#define W_SRA(rd, rs1, rs2) RTYPE(0x20, rs2, rs1, 0x05, rd, 0x33) +#define W_SRAI(rd, rs, imm) ITYPE(0x400 | ((imm) & 63), rs, 0x05, rd, 0x13) +#define W_SLT(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x02, rd, 0x33) +#define W_SLTU(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x03, rd, 0x33) +#define W_SLTI(rd, rs, imm) ITYPE(imm, rs, 0x02, rd, 0x13) +#define W_SLTIU(rd, rs, imm) ITYPE(imm, rs, 0x03, rd, 0x13) +#define W_LB(rd, ofs, rs) ITYPE(ofs, rs, 0x00, rd, 0x03) +#define W_LH(rd, ofs, rs) ITYPE(ofs, rs, 0x01, rd, 0x03) +#define W_LW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x03) +#define W_LD(rd, ofs, rs) ITYPE(ofs, rs, 0x03, rd, 0x03) +#define W_LBU(rd, ofs, rs) ITYPE(ofs, rs, 0x04, rd, 0x03) +#define W_LHU(rd, ofs, rs) ITYPE(ofs, rs, 0x05, rd, 0x03) +#define W_LWU(rd, ofs, rs) ITYPE(ofs, rs, 0x06, rd, 0x03) +#define W_SB(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x00, 0x23) +#define W_SH(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x01, 0x23) +#define W_SW(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x02, 0x23) +#define W_SD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x23) +#define W_LUI(rd, imm) UTYPE(imm, rd, 0x37) +#define W_AUIPC(rd, imm) UTYPE(imm, rd, 0x17) +#define W_JAL(rd, imm) UTYPE(imm, rd, 0x6f) +#define W_JALR(rd, rs, imm) ITYPE(imm, rs, 0x00, rd, 0x67) +#define W_BXX(xx, rs1, rs2, ofs) STYPE(ofs, rs2, rs1, xx, 0x63) + +#define W_FADD_D(rd, rs1, rs2) RTYPE(0x01, rs2, rs1, 0x07, rd, 0x53) +#define W_FSUB_D(rd, rs1, rs2) RTYPE(0x05, rs2, rs1, 0x07, rd, 0x53) +#define W_FMUL_D(rd, rs1, rs2) RTYPE(0x09, rs2, rs1, 0x07, rd, 0x53) +#define W_FDIV_D(rd, rs1, rs2) RTYPE(0x0d, rs2, rs1, 0x07, rd, 0x53) +#define W_FADD_S(rd, rs1, rs2) RTYPE(0x00, rs2, rs1, 0x07, rd, 0x53) +#define W_FSUB_S(rd, rs1, rs2) RTYPE(0x04, rs2, rs1, 0x07, rd, 0x53) +#define W_FMUL_S(rd, rs1, rs2) RTYPE(0x08, rs2, rs1, 0x07, rd, 0x53) +#define W_FDIV_S(rd, rs1, rs2) RTYPE(0x0c, rs2, rs1, 0x07, rd, 0x53) +#define W_FEQ_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x02, rd, 0x53) +#define W_FLT_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x01, rd, 0x53) +#define W_FLE_D(rd, rs1, rs2) RTYPE(0x51, rs2, rs1, 0x00, rd, 0x53) +#define W_FEQ_S(rd, rs1, rs2) RTYPE(0x50, rs2, rs1, 0x02, rd, 0x53) +#define W_FLT_S(rd, rs1, rs2) RTYPE(0x50, rs2, rs1, 0x01, rd, 0x53) +#define W_FLE_S(rd, rs1, rs2) RTYPE(0x50, rs2, rs1, 0x00, rd, 0x53) +#define W_FLD(rd, ofs, rs) ITYPE(ofs, rs, 0x03, rd, 0x07) +#define W_FLW(rd, ofs, rs) ITYPE(ofs, rs, 0x02, rd, 0x07) +#define W_FSD(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x03, 0x27) +#define W_FSW(rs2, ofs, rs1) STYPE(ofs, rs2, rs1, 0x02, 0x27) +#define W_FSGNJ_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x00, rd, 0x53) +#define W_FSGNJ_S(rd, rs1, rs2) RTYPE(0x10, rs2, rs1, 0x00, rd, 0x53) +#define W_FSGNJN_D(rd, rs1, rs2) RTYPE(0x11, rs2, rs1, 0x01, rd, 0x53) +#define W_FSGNJN_S(rd, rs1, rs2) RTYPE(0x10, rs2, rs1, 0x01, rd, 0x53) + +#define W_FCVT_D_W(rd, rs) RTYPE(0x69, 0, rs, 0x00, rd, 0x53) +#define W_FCVT_D_WU(rd, rs) RTYPE(0x69, 1, rs, 0x00, rd, 0x53) +#define W_FCVT_D_L(rd, rs) RTYPE(0x69, 2, rs, 0x07, rd, 0x53) +#define W_FCVT_D_LU(rd, rs) RTYPE(0x69, 3, rs, 0x07, rd, 0x53) +#define W_FCVT_S_W(rd, rs) RTYPE(0x68, 0, rs, 0x07, rd, 0x53) +#define W_FCVT_S_WU(rd, rs) RTYPE(0x68, 1, rs, 0x07, rd, 0x53) +#define W_FCVT_S_L(rd, rs) RTYPE(0x68, 2, rs, 0x07, rd, 0x53) +#define W_FCVT_S_LU(rd, rs) RTYPE(0x68, 3, rs, 0x07, rd, 0x53) + +#define W_FCVT_W_D(rd, rs, rm) RTYPE(0x61, 0, rs, rm, rd, 0x53) +#define W_FCVT_WU_D(rd, rs, rm) RTYPE(0x61, 1, rs, rm, rd, 0x53) +#define W_FCVT_L_D(rd, rs, rm) RTYPE(0x61, 2, rs, rm, rd, 0x53) +#define W_FCVT_LU_D(rd, rs, rm) RTYPE(0x61, 3, rs, rm, rd, 0x53) +#define W_FCVT_W_S(rd, rs, rm) RTYPE(0x60, 0, rs, rm, rd, 0x53) +#define W_FCVT_WU_S(rd, rs, rm) RTYPE(0x60, 1, rs, rm, rd, 0x53) +#define W_FCVT_L_S(rd, rs, rm) RTYPE(0x60, 2, rs, rm, rd, 0x53) +#define W_FCVT_LU_S(rd, rs, rm) RTYPE(0x60, 3, rs, rm, rd, 0x53) + +#define W_FCVT_D_S(rd, rs) RTYPE(0x21, 0, rs, 0x00, rd, 0x53) +#define W_FCVT_S_D(rd, rs) RTYPE(0x20, 1, rs, 0x07, rd, 0x53) + +#define W_FMV_X_D(rd, rs) RTYPE(0x71, 0, rs, 0x00, rd, 0x53) +#define W_FMV_X_W(rd, rs) RTYPE(0x70, 0, rs, 0x00, rd, 0x53) + +// Compressed instructions +#define C_MV(rd, rs) MAKE_CODE16(inst, code, 0x8002 | ((rd) << 7) | ((rs) << 2)) +#define C_LI(rd, imm) MAKE_CODE16(inst, code, 0x4001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_LUI(rd, imm) MAKE_CODE16(inst, code, 0x6001 | (IMM(imm, 17, 17) << 12) | ((rd) << 7) | (IMM(imm, 16, 12) << 2)) +#define C_ADD(rd, rs) MAKE_CODE16(inst, code, 0x9002 | ((rd) << 7) | ((rs) << 2)) +#define C_ADDW(rd, rs) MAKE_CODE16(inst, code, 0x9c21 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_ADDI(rd, imm) MAKE_CODE16(inst, code, 0x0001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_ADDIW(rd, imm) MAKE_CODE16(inst, code, 0x2001 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_ADDI16SP(imm) MAKE_CODE16(inst, code, 0x6101 | (IMM(imm, 9, 9) << 12) | (IMM(imm, 4, 4) << 6) | (IMM(imm, 6, 6) << 5) | (IMM(imm, 8, 7) << 3) | (IMM(imm, 5, 5) << 2)) +#define C_SUB(rd, rs) MAKE_CODE16(inst, code, 0x8c01 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_SUBW(rd, rs) MAKE_CODE16(inst, code, 0x9c01 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_AND(rd, rs) MAKE_CODE16(inst, code, 0x8c61 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_ANDI(rd, imm) MAKE_CODE16(inst, code, 0x8801 | (IMM(imm, 5, 5) << 12) | (to_rvc_reg(rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_OR(rd, rs) MAKE_CODE16(inst, code, 0x8c41 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_XOR(rd, rs) MAKE_CODE16(inst, code, 0x8c21 | (to_rvc_reg(rd) << 7) | (to_rvc_reg(rs) << 2)) +#define C_SLLI(rd, imm) MAKE_CODE16(inst, code, 0x0002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_SRLI(rd, imm) MAKE_CODE16(inst, code, 0x8001 | (IMM(imm, 5, 5) << 12) | (to_rvc_reg(rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_SRAI(rd, imm) MAKE_CODE16(inst, code, 0x8401 | (IMM(imm, 5, 5) << 12) | (to_rvc_reg(rd) << 7) | (IMM(imm, 4, 0) << 2)) +#define C_LW(rd, imm, rs) MAKE_CODE16(inst, code, 0x4000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 2, 2) << 6) | (IMM(imm, 6, 6) << 5) | (to_rvc_reg(rd) << 2)) +#define C_LD(rd, imm, rs) MAKE_CODE16(inst, code, 0x6000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rd) << 2)) +#define C_SW(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xc000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rs2) << 2)) +#define C_SD(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xe000 | (IMM(imm, 5, 3) << 10) | (to_rvc_reg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_reg(rs2) << 2)) +#define C_LDSP(rd, imm) MAKE_CODE16(inst, code, 0x6002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) +#define C_SDSP(rs, imm) MAKE_CODE16(inst, code, 0xe002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) +#define C_J() MAKE_CODE16(inst, code, 0xa001) +#define C_JR(rs) MAKE_CODE16(inst, code, 0x8002 | ((rs) << 7)) +#define C_JALR(rs) MAKE_CODE16(inst, code, 0x9002 | ((rs) << 7)) +#define C_BEQZ(rs) MAKE_CODE16(inst, code, 0xc001 | (to_rvc_reg(rs) << 7)) +#define C_BNEZ(rs) MAKE_CODE16(inst, code, 0xe001 | (to_rvc_reg(rs) << 7)) + +#define C_FLD(rd, imm, rs) MAKE_CODE16(inst, code, 0x2000 | (IMM(imm, 5, 3) << 10) | (to_rvc_freg(rs) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_freg(rd) << 2)) +#define C_FSD(rs2, imm, rs1) MAKE_CODE16(inst, code, 0xa000 | (IMM(imm, 5, 3) << 10) | (to_rvc_freg(rs1) << 7) | (IMM(imm, 7, 6) << 5) | (to_rvc_freg(rs2) << 2)) +#define C_FLDSP(rd, imm) MAKE_CODE16(inst, code, 0x2002 | (IMM(imm, 5, 5) << 12) | ((rd) << 7) | (IMM(imm, 4, 3) << 5) | (IMM(imm, 8, 6) << 2)) +#define C_FSDSP(rs, imm) MAKE_CODE16(inst, code, 0xa002 | (IMM(imm, 5, 3) << 10) | (IMM(imm, 8, 6) << 7) | ((rs) << 2)) + +// Pseudo instructions +#define P_RET() C_JR(RA) +#define P_LI(rd, imm) W_ADDI(rd, ZERO, imm) +#define P_NEG(rd, rs) W_SUB(rd, ZERO, rs) +#define P_NOT(rd, rs) W_XORI(rd, rs, -1) +#define P_SEXT_B(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 56); else W_SLLI(rd, rs, 56); C_SRAI(rd, 56); } while (0) +#define P_SEXT_H(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 48); else W_SLLI(rd, rs, 48); C_SRAI(rd, 48); } while (0) +#define P_SEXT_W(rd, rs) do { if ((rd) == (rs)) C_ADDIW(rd, 0); else W_ADDIW(rd, rs, 0); } while (0) +#define P_ZEXT_B(rd, rs) W_ANDI(rd, rs, 0xff) +#define P_ZEXT_H(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 48); else W_SLLI(rd, rs, 48); C_SRLI(rd, 48); } while (0) +#define P_ZEXT_W(rd, rs) do { if ((rd) == (rs) && (rs) != 0) C_SLLI(rd, 32); else W_SLLI(rd, rs, 32); C_SRLI(rd, 32); } while (0) +#define P_SEQZ(rd, rs) W_SLTIU(rd, rs, 1) +#define P_SNEZ(rd, rs) W_SLTU(rd, ZERO, rs) +#define P_SLTZ(rd, rs) W_SLT(rd, rs, ZERO) +#define P_SGTZ(rd, rs) W_SLT(rd, ZERO, rs) + +#define P_FMV_D(rd, rs) W_FSGNJ_D(rd, rs, rs) +#define P_FMV_S(rd, rs) W_FSGNJ_S(rd, rs, rs) +#define P_FNEG_D(rd, rs) W_FSGNJN_D(rd, rs, rs) +#define P_FNEG_S(rd, rs) W_FSGNJN_S(rd, rs, rs) + +inline bool is_rvc_reg(int reg) { return reg >= 8 && reg <= 15; } // X8~X15 +inline int to_rvc_reg(int reg) { return reg - 8; } +#define is_rvc_freg is_rvc_reg +#define to_rvc_freg to_rvc_reg diff --git a/src/as/asm_code.h b/src/as/asm_code.h index b036a1bfe..32c117d7c 100644 --- a/src/as/asm_code.h +++ b/src/as/asm_code.h @@ -26,9 +26,19 @@ void assemble_inst(Inst *inst, const ParseInfo *info, Code *code); #define MAKE_CODE(inst, code, ...) do { unsigned char buf[] = {__VA_ARGS__}; make_code(inst, code, buf, sizeof(buf)); } while (0) #endif +#ifndef MAKE_CODE16 +#define MAKE_CODE16(inst, code, ...) do { unsigned short buf[] = {__VA_ARGS__}; make_code16(inst, code, buf, sizeof(buf)); } while (0) +#endif + +#ifndef MAKE_CODE32 +#define MAKE_CODE32(inst, code, ...) do { unsigned int buf[] = {__VA_ARGS__}; make_code32(inst, code, buf, sizeof(buf)); } while (0) +#endif + #define IM8(x) (x) #define IM16(x) (x), ((x) >> 8) #define IM32(x) (x), ((x) >> 8), ((x) >> 16), ((x) >> 24) #define IM64(x) (x), ((x) >> 8), ((x) >> 16), ((x) >> 24), ((x) >> 32), ((x) >> 40), ((x) >> 48), ((x) >> 56) void make_code(Inst *inst, Code *code, unsigned char *buf, int len); +void make_code16(Inst *inst, Code *code, unsigned short *buf, int len); +void make_code32(Inst *inst, Code *code, unsigned int *buf, int len);