Compare commits
2 Commits
d167a8ba96
...
4ddad7b456
| Author | SHA1 | Date | |
|---|---|---|---|
| 4ddad7b456 | |||
| 8c7af571c2 |
@@ -11,128 +11,128 @@
|
||||
static const scc_type_abi_t scc_win_x64_type_abi[] = {
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_UNKNOWN,
|
||||
.ir_type = SCC_IR_TYPE_UNKNOWN,
|
||||
.ir_type = SCC_IR_TYPE_unknown,
|
||||
.size = 0,
|
||||
.alignment = 0,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_VOID,
|
||||
.ir_type = SCC_IR_TYPE_VOID,
|
||||
.ir_type = SCC_IR_TYPE_void,
|
||||
.size = 0,
|
||||
.alignment = 0,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_BOOL,
|
||||
.ir_type = SCC_IR_TYPE_U8,
|
||||
.ir_type = SCC_IR_TYPE_u8,
|
||||
.size = 1,
|
||||
.alignment = 1,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_CHAR,
|
||||
.ir_type = SCC_IR_TYPE_I8,
|
||||
.ir_type = SCC_IR_TYPE_i8,
|
||||
.size = 1,
|
||||
.alignment = 1,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_CHAR,
|
||||
.ir_type = SCC_IR_TYPE_I8,
|
||||
.ir_type = SCC_IR_TYPE_i8,
|
||||
.size = 1,
|
||||
.alignment = 1,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_CHAR,
|
||||
.ir_type = SCC_IR_TYPE_U8,
|
||||
.ir_type = SCC_IR_TYPE_u8,
|
||||
.size = 1,
|
||||
.alignment = 1,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_SHORT,
|
||||
.ir_type = SCC_IR_TYPE_I16,
|
||||
.ir_type = SCC_IR_TYPE_i16,
|
||||
.size = 2,
|
||||
.alignment = 2,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_SHORT,
|
||||
.ir_type = SCC_IR_TYPE_I16,
|
||||
.ir_type = SCC_IR_TYPE_i16,
|
||||
.size = 2,
|
||||
.alignment = 2,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_SHORT,
|
||||
.ir_type = SCC_IR_TYPE_U16,
|
||||
.ir_type = SCC_IR_TYPE_u16,
|
||||
.size = 2,
|
||||
.alignment = 2,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_INT,
|
||||
.ir_type = SCC_IR_TYPE_I32,
|
||||
.ir_type = SCC_IR_TYPE_i32,
|
||||
.size = 4,
|
||||
.alignment = 4,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_INT,
|
||||
.ir_type = SCC_IR_TYPE_I32,
|
||||
.ir_type = SCC_IR_TYPE_i32,
|
||||
.size = 4,
|
||||
.alignment = 4,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_INT,
|
||||
.ir_type = SCC_IR_TYPE_U32,
|
||||
.ir_type = SCC_IR_TYPE_u32,
|
||||
.size = 4,
|
||||
.alignment = 4,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_LONG,
|
||||
.ir_type = SCC_IR_TYPE_I32,
|
||||
.ir_type = SCC_IR_TYPE_i32,
|
||||
.size = 4,
|
||||
.alignment = 4,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_LONG,
|
||||
.ir_type = SCC_IR_TYPE_I32,
|
||||
.ir_type = SCC_IR_TYPE_i32,
|
||||
.size = 4,
|
||||
.alignment = 4,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG,
|
||||
.ir_type = SCC_IR_TYPE_U32,
|
||||
.ir_type = SCC_IR_TYPE_u32,
|
||||
.size = 4,
|
||||
.alignment = 4,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_LONG_LONG,
|
||||
.ir_type = SCC_IR_TYPE_I64,
|
||||
.ir_type = SCC_IR_TYPE_i64,
|
||||
.size = 8,
|
||||
.alignment = 8,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_SIGNED_LONG_LONG,
|
||||
.ir_type = SCC_IR_TYPE_I64,
|
||||
.ir_type = SCC_IR_TYPE_i64,
|
||||
.size = 8,
|
||||
.alignment = 8,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_UNSIGNED_LONG_LONG,
|
||||
.ir_type = SCC_IR_TYPE_I64,
|
||||
.ir_type = SCC_IR_TYPE_i64,
|
||||
.size = 8,
|
||||
.alignment = 8,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_FLOAT,
|
||||
.ir_type = SCC_IR_TYPE_F32,
|
||||
.ir_type = SCC_IR_TYPE_f32,
|
||||
.size = 4,
|
||||
.alignment = 4,
|
||||
},
|
||||
{
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_DOUBLE,
|
||||
.ir_type = SCC_IR_TYPE_F64,
|
||||
.ir_type = SCC_IR_TYPE_f64,
|
||||
.size = 8,
|
||||
.alignment = 8,
|
||||
},
|
||||
{
|
||||
// NULL
|
||||
.ast_type = SCC_AST_BUILTIN_TYPE_UNKNOWN,
|
||||
.ir_type = SCC_IR_TYPE_UNKNOWN,
|
||||
.ir_type = SCC_IR_TYPE_unknown,
|
||||
.size = 0,
|
||||
.alignment = 0,
|
||||
},
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define __SCC_AST2IR_H__
|
||||
|
||||
#include "scc_type_abi.h"
|
||||
#include <ir_builder.h>
|
||||
#include <scc_ast.h>
|
||||
#include <scc_ir.h>
|
||||
|
||||
@@ -13,7 +14,9 @@ typedef struct {
|
||||
const scc_type_abi_t *abi;
|
||||
} scc_ast2ir_ctx_t;
|
||||
|
||||
void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_type_abi_t *abi);
|
||||
void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_type_abi_t *abi,
|
||||
scc_ir_cprog_t *cprog);
|
||||
void scc_ast2ir_ctx_drop(scc_ast2ir_ctx_t *ctx);
|
||||
|
||||
void scc_ast2ir_translation_unit(scc_ast2ir_ctx_t *ctx,
|
||||
scc_ast_translation_unit_t *tu);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
#include <ir_builtin.h>
|
||||
#include <scc_ast2ir.h>
|
||||
|
||||
scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||
@@ -12,7 +11,7 @@ scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||
switch (ast_type->base.type) {
|
||||
case SCC_AST_TYPE_BUILTIN: {
|
||||
// 映射内置类型
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_I32);
|
||||
scc_ir_type_init(&ir_type, SCC_IR_TYPE_i32);
|
||||
// TODO: 根据具体内置类型设置
|
||||
break;
|
||||
}
|
||||
@@ -64,20 +63,17 @@ scc_ir_type_ref_t scc_ast2ir_type(scc_ast2ir_ctx_t *ctx,
|
||||
break;
|
||||
}
|
||||
|
||||
// SCC_AST_TYPE_BUILTIN, // 内置类型
|
||||
// SCC_AST_TYPE_POINTER, // 指针类型
|
||||
// SCC_AST_TYPE_ARRAY, // 数组类型
|
||||
// SCC_AST_TYPE_FUNCTION, // 函数类型
|
||||
// SCC_AST_TYPE_STRUCT, // 结构体类型
|
||||
// SCC_AST_TYPE_UNION, // 联合类型
|
||||
// SCC_AST_TYPE_ENUM, // 枚举类型
|
||||
// SCC_AST_TYPE_TYPEDEF, // typedef 类型
|
||||
case SCC_AST_TYPE_TYPEDEF:
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_FATAL("Unsupported AST type: %d", ast_type->base.type);
|
||||
return 0;
|
||||
}
|
||||
return scc_ir_ctx_new_type(&ctx->builder.ctx, &ir_type);
|
||||
return scc_ir_builder_type(&ctx->builder, &ir_type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,22 +226,32 @@ scc_ir_node_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
|
||||
// SCC_AST_OP_POSTFIX_INCREMENT, // ++ (后缀)
|
||||
// SCC_AST_OP_POSTFIX_DECREMENT, // -- (后缀)
|
||||
switch (expr->unary.op) {
|
||||
case SCC_AST_OP_UNARY_MINUS:
|
||||
case SCC_AST_OP_UNARY_MINUS: {
|
||||
// 负号
|
||||
// 实现为0 - operand
|
||||
return scc_ir_builder_binop(
|
||||
&ctx->builder, SCC_IR_OP_SUB,
|
||||
scc_ir_ctx_get_builtin_zero(&ctx->builder.ctx), operand);
|
||||
scc_ir_const_int_t value;
|
||||
scc_ir_type_ref_t type_ref = scc_ir_builder_type_i32(&ctx->builder);
|
||||
value.int32 = 0;
|
||||
scc_ir_node_ref_t zero_ref =
|
||||
scc_ir_builder_const_int(&ctx->builder, type_ref, value);
|
||||
return scc_ir_builder_binop(&ctx->builder, SCC_IR_OP_SUB, zero_ref,
|
||||
operand);
|
||||
}
|
||||
case SCC_AST_OP_BITWISE_NOT:
|
||||
// 按位取反
|
||||
return scc_ir_builder_binop(&ctx->builder, SCC_IR_OP_NOT, operand,
|
||||
0);
|
||||
case SCC_AST_OP_LOGICAL_NOT:
|
||||
case SCC_AST_OP_LOGICAL_NOT: {
|
||||
// 逻辑非
|
||||
// 实现为与0比较
|
||||
return scc_ir_builder_binop(
|
||||
&ctx->builder, SCC_IR_OP_EQ,
|
||||
scc_ir_ctx_get_builtin_zero(&ctx->builder.ctx), operand);
|
||||
scc_ir_const_int_t value;
|
||||
scc_ir_type_ref_t type_ref = scc_ir_builder_type_i32(&ctx->builder);
|
||||
value.int32 = 0;
|
||||
scc_ir_node_ref_t zero_ref =
|
||||
scc_ir_builder_const_int(&ctx->builder, type_ref, value);
|
||||
return scc_ir_builder_binop(&ctx->builder, SCC_IR_OP_EQ, zero_ref,
|
||||
operand);
|
||||
}
|
||||
default:
|
||||
LOG_FATAL("Unsupported unary operator: %d", expr->unary.op);
|
||||
return 0;
|
||||
@@ -272,6 +278,10 @@ scc_ir_node_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
|
||||
// 创建调用节点(需要查找函数定义)
|
||||
scc_ir_func_ref_t func = (scc_ir_node_ref_t)(usize)scc_hashtable_get(
|
||||
&ctx->symtab, expr->call.callee->identifier._target->name);
|
||||
if (!func) {
|
||||
LOG_ERROR("Function %s not found",
|
||||
expr->call.callee->identifier._target->name);
|
||||
}
|
||||
scc_ir_node_ref_t node =
|
||||
scc_ir_builder_call(&ctx->builder, func, args.data, args.size);
|
||||
scc_vec_free(args);
|
||||
@@ -294,13 +304,18 @@ scc_ir_node_ref_t scc_ast2ir_expr(scc_ast2ir_ctx_t *ctx, scc_ast_expr_t *expr,
|
||||
for (usize i = 0; i < scc_strlen(expr->literal.lexme); i++) {
|
||||
int_lit = int_lit * 10 + (expr->literal.lexme[i] - '0');
|
||||
}
|
||||
return scc_ir_ctx_get_i32_const(&ctx->builder.ctx, int_lit);
|
||||
scc_ir_type_ref_t type_ref = scc_ir_builder_type_i32(&ctx->builder);
|
||||
scc_ir_const_int_t value;
|
||||
value.int32 = int_lit;
|
||||
return scc_ir_builder_const_int(&ctx->builder, type_ref, value);
|
||||
}
|
||||
|
||||
// SCC_AST_EXPR_INT_LITERAL, // 整数字面量
|
||||
// SCC_AST_EXPR_FLOAT_LITERAL, // 浮点字面量
|
||||
// SCC_AST_EXPR_CHAR_LITERAL, // 字符字面量
|
||||
// SCC_AST_EXPR_STRING_LITERAL, // 字符串字面量
|
||||
// case SCC_AST_EXPR_STRING_LITERAL: {
|
||||
// return scc_ir_builder_store();
|
||||
// }
|
||||
|
||||
case SCC_AST_EXPR_IDENTIFIER: {
|
||||
if (expr->identifier._target == null) {
|
||||
@@ -550,7 +565,6 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl) {
|
||||
scc_ir_builder_func(&ctx->builder, func_type_ref, decl->name);
|
||||
scc_hashtable_set(&ctx->symtab, decl->name,
|
||||
(void *)(usize)func_ref);
|
||||
scc_vec_push(ctx->builder.cprog.func_decls, func_ref);
|
||||
}
|
||||
|
||||
if (decl->func.body == null) {
|
||||
@@ -559,7 +573,8 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl) {
|
||||
}
|
||||
|
||||
scc_ir_builder_begin_func(&ctx->builder, func_ref, null);
|
||||
scc_ir_func_t *func = scc_ir_ctx_get_func(&ctx->builder.ctx, func_ref);
|
||||
scc_ir_func_t *func =
|
||||
scc_ir_module_get_func(ctx->builder.ctx.module, func_ref);
|
||||
Assert(func != null);
|
||||
scc_ir_builder_begin_bblock(&ctx->builder, "entry");
|
||||
scc_vec_foreach(decl->func.type->function.params, i) {
|
||||
@@ -568,7 +583,7 @@ void scc_ast2ir_decl(scc_ast2ir_ctx_t *ctx, scc_ast_decl_t *decl) {
|
||||
|
||||
scc_ir_node_ref_t param_node_ref = scc_vec_at(func->params, i);
|
||||
scc_ir_node_t *param_node =
|
||||
scc_ir_ctx_get_node(&ctx->builder.ctx, param_node_ref);
|
||||
scc_ir_module_get_node(ctx->builder.ctx.module, param_node_ref);
|
||||
Assert(param_node != null);
|
||||
param_node->name = param->name;
|
||||
scc_hashtable_set(&ctx->node2ir, param,
|
||||
@@ -620,11 +635,18 @@ static int scc_cmp_node(const void *key1, const void *key2) {
|
||||
return (u32)(usize)key1 - (u32)(usize)key2;
|
||||
}
|
||||
|
||||
void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_type_abi_t *abi) {
|
||||
void scc_ast2ir_ctx_init(scc_ast2ir_ctx_t *ctx, const scc_type_abi_t *abi,
|
||||
scc_ir_cprog_t *cprog) {
|
||||
Assert(ctx != null);
|
||||
ctx->abi = abi;
|
||||
scc_ir_builder_init(&ctx->builder);
|
||||
scc_ir_builder_init(&ctx->builder, cprog);
|
||||
scc_hashtable_init(&ctx->node2ir, scc_hash_node, scc_cmp_node);
|
||||
scc_hashtable_init(&ctx->symtab, (scc_hashtable_hash_func_t)scc_strhash32,
|
||||
(scc_hashtable_equal_func_t)scc_strcmp);
|
||||
}
|
||||
|
||||
void scc_ast2ir_ctx_drop(scc_ast2ir_ctx_t *ctx) {
|
||||
scc_ir_builder_drop(&ctx->builder);
|
||||
scc_hashtable_drop(&ctx->node2ir);
|
||||
scc_hashtable_drop(&ctx->symtab);
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
#ifndef __SCC_IR_BASE_H__
|
||||
#define __SCC_IR_BASE_H__
|
||||
|
||||
#include "ir_def.h"
|
||||
|
||||
void scc_ir_type_init(scc_ir_type_t *in, scc_ir_type_tag_t tag);
|
||||
void scc_ir_bblock_init(scc_ir_bblock_t *in, const char *label);
|
||||
void scc_ir_func_init(scc_ir_func_t *in, const char *name);
|
||||
|
||||
// node name can be null ptr
|
||||
void scc_ir_node_init(scc_ir_node_t *in, const char *name,
|
||||
scc_ir_node_tag_t tag);
|
||||
|
||||
void scc_ir_cprog_init(scc_ir_cprog_t *in);
|
||||
void scc_ir_cprog_drop(scc_ir_cprog_t *in);
|
||||
|
||||
#endif /* __SCC_IR_BASE_H__ */
|
||||
@@ -2,8 +2,7 @@
|
||||
#define __SCC_IR_BUILDER_H__
|
||||
|
||||
#include "ir_ctx.h"
|
||||
#include "ir_def.h"
|
||||
#include <scc_core.h>
|
||||
#include "scc_ir.h"
|
||||
|
||||
typedef struct scc_ir_builder scc_ir_builder_t;
|
||||
|
||||
@@ -17,18 +16,16 @@ typedef struct scc_ir_builder scc_ir_builder_t;
|
||||
* - 当前构建位置(函数、基本块)
|
||||
*/
|
||||
struct scc_ir_builder {
|
||||
scc_ir_cprog_ctx_t ctx; /**< 核心上下文 */
|
||||
scc_ir_cprog_t cprog;
|
||||
scc_hashtable_t func_decl_set;
|
||||
// 当前构建位置
|
||||
scc_ir_func_ref_t current_func; /**< 当前正在构建的函数 */
|
||||
scc_ir_bblock_ref_t current_bblock; /**< 当前基本块 */
|
||||
scc_ir_cprog_t *cprog;
|
||||
scc_ir_ctx_t ctx; ///< 核心上下文
|
||||
scc_ir_func_ref_t current_func; ///< 当前正在构建的函数
|
||||
scc_ir_bblock_ref_t current_bblock; ///< 当前基本块
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化 IR 构建器
|
||||
*/
|
||||
void scc_ir_builder_init(scc_ir_builder_t *builder);
|
||||
void scc_ir_builder_init(scc_ir_builder_t *builder, scc_ir_cprog_t *cprog);
|
||||
|
||||
/**
|
||||
* @brief 销毁 IR 构建器及其所有资源
|
||||
@@ -39,6 +36,46 @@ scc_ir_func_ref_t scc_ir_builder_func(scc_ir_builder_t *builder,
|
||||
scc_ir_type_ref_t type_ref,
|
||||
const char *name);
|
||||
|
||||
scc_ir_type_ref_t scc_ir_builder_type(scc_ir_builder_t *builder,
|
||||
const scc_ir_type_t *type_desc);
|
||||
|
||||
// TODO
|
||||
static inline scc_ir_node_ref_t
|
||||
scc_ir_builder_const_int(scc_ir_builder_t *builder, scc_ir_type_ref_t type,
|
||||
scc_ir_const_int_t value) {
|
||||
scc_ir_node_t node;
|
||||
scc_ir_node_init(&node, null, SCC_IR_NODE_CONST_INT);
|
||||
node.data.const_int = value;
|
||||
node.type = type;
|
||||
return scc_ir_module_add_node(&builder->cprog->module, &node);
|
||||
}
|
||||
|
||||
#define SCC_IR_BUILDER_TYPE_FUNC(scc_type) \
|
||||
[[maybe_unused]] static inline scc_ir_type_ref_t \
|
||||
scc_ir_builder_type_##scc_type(scc_ir_builder_t *builder) { \
|
||||
scc_ir_type_t type_desc; \
|
||||
scc_ir_type_init(&type_desc, SCC_IR_TYPE_##scc_type); \
|
||||
return scc_ir_ctx_get_type(&builder->ctx, &type_desc); \
|
||||
}
|
||||
|
||||
SCC_IR_BUILDER_TYPE_FUNC(unknown)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(void)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(i8)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(i16)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(i32)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(i64)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(i128)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(u8)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(u16)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(u32)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(u64)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(u128)
|
||||
// SCC_IR_BUILDER_TYPE_FUNC(f8)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(f16)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(f32)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(f64)
|
||||
SCC_IR_BUILDER_TYPE_FUNC(f128)
|
||||
|
||||
/**
|
||||
* @brief 开始构建函数
|
||||
* @param func_ref 函数引用
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
#ifndef __SCC_IR_BUILTIN_H__
|
||||
#define __SCC_IR_BUILTIN_H__
|
||||
|
||||
#include "ir_def.h"
|
||||
|
||||
extern scc_ir_type_t scc_ir_builtin_i32;
|
||||
extern scc_ir_node_t scc_ir_builtin_zero;
|
||||
|
||||
#endif /* __SCC_IR_BUILTIN_H__ */
|
||||
@@ -1,194 +1,32 @@
|
||||
#ifndef __SCC_IR_CTX_H__
|
||||
#define __SCC_IR_CTX_H__
|
||||
|
||||
#include "ir_base.h"
|
||||
#include "ir_def.h"
|
||||
#include "ir_prog.h"
|
||||
#include <scc_hashtable.h>
|
||||
|
||||
#define SCC_IR_REF_NULL 0
|
||||
|
||||
typedef struct {
|
||||
unsigned int node_uid;
|
||||
unsigned int type_uid;
|
||||
unsigned int bblock_uid;
|
||||
unsigned int func_uid;
|
||||
scc_ir_module_t *module; // 关联的模块(用于实际存储)
|
||||
scc_hashtable_t type_uniquing; // 类型哈希表:hash -> type_ref
|
||||
scc_hashtable_t const_pool; // 常量哈希表:hash -> node_ref
|
||||
scc_hashtable_t func_decl_set; // 函数声明集合:name -> func_ref
|
||||
} scc_ir_ctx_t;
|
||||
|
||||
SCC_VEC(scc_ir_node_t) nodes;
|
||||
SCC_VEC(scc_ir_type_t) types;
|
||||
SCC_VEC(scc_ir_bblock_t) bblocks;
|
||||
SCC_VEC(scc_ir_func_t) funcs;
|
||||
void scc_ir_ctx_init(scc_ir_ctx_t *ctx, scc_ir_module_t *module);
|
||||
void scc_ir_ctx_drop(scc_ir_ctx_t *ctx);
|
||||
|
||||
// UID -> 索引 映射
|
||||
scc_hashtable_t uid2nodes;
|
||||
scc_hashtable_t uid2types;
|
||||
scc_hashtable_t uid2bblocks;
|
||||
scc_hashtable_t uid2funcs;
|
||||
// 获取唯一类型,若不存在则创建并返回新引用
|
||||
scc_ir_type_ref_t scc_ir_ctx_get_type(scc_ir_ctx_t *ctx,
|
||||
const scc_ir_type_t *type_desc);
|
||||
|
||||
// 类型去重表(类型键 -> 类型引用)
|
||||
scc_hashtable_t type_uniquing;
|
||||
// 获取唯一常量(例如整数常量)
|
||||
// scc_ir_node_ref_t scc_ir_ctx_get_const_int(scc_ir_ctx_t *ctx,
|
||||
// scc_ir_type_ref_t type, i64
|
||||
// value);
|
||||
|
||||
// 常量池(常量键 -> 节点引用)
|
||||
scc_hashtable_t const_pool;
|
||||
} scc_ir_cprog_ctx_t;
|
||||
|
||||
/**
|
||||
* @brief 初始化IR上下文
|
||||
* @param ctx 上下文指针
|
||||
*/
|
||||
void scc_ir_ctx_init(scc_ir_cprog_ctx_t *ctx);
|
||||
|
||||
/**
|
||||
* @brief 销毁IR上下文及其所有资源
|
||||
* @param ctx 上下文指针
|
||||
*/
|
||||
void scc_ir_ctx_drop(scc_ir_cprog_ctx_t *ctx);
|
||||
|
||||
/**
|
||||
* @brief 重置IR上下文(清空所有数据但保留内存)
|
||||
* @param ctx 上下文指针
|
||||
*/
|
||||
void scc_ir_ctx_reset(scc_ir_cprog_ctx_t *ctx);
|
||||
|
||||
/**
|
||||
* @brief 创建新的类型
|
||||
* @param ctx 上下文指针
|
||||
* @param type 类型数据(会被拷贝)
|
||||
* @return 类型引用(0表示失败)
|
||||
*/
|
||||
scc_ir_type_ref_t scc_ir_ctx_new_type(scc_ir_cprog_ctx_t *ctx,
|
||||
const scc_ir_type_t *type);
|
||||
|
||||
/**
|
||||
* @brief 创建新的节点
|
||||
* @param ctx 上下文指针
|
||||
* @param node 节点数据(会被拷贝)
|
||||
* @return 节点引用(0表示失败)
|
||||
*/
|
||||
scc_ir_node_ref_t scc_ir_ctx_new_node(scc_ir_cprog_ctx_t *ctx,
|
||||
const scc_ir_node_t *node);
|
||||
|
||||
/**
|
||||
* @brief 创建新的基本块
|
||||
* @param ctx 上下文指针
|
||||
* @param bblock 基本块数据(会被拷贝)
|
||||
* @return 基本块引用(0表示失败)
|
||||
*/
|
||||
scc_ir_bblock_ref_t scc_ir_ctx_new_bblock(scc_ir_cprog_ctx_t *ctx,
|
||||
const scc_ir_bblock_t *bblock);
|
||||
|
||||
/**
|
||||
* @brief 创建新的函数
|
||||
* @param ctx 上下文指针
|
||||
* @param func 函数数据(会被拷贝)
|
||||
* @return 函数引用(0表示失败)
|
||||
*/
|
||||
scc_ir_func_ref_t scc_ir_ctx_new_func(scc_ir_cprog_ctx_t *ctx,
|
||||
const scc_ir_func_t *func);
|
||||
|
||||
/**
|
||||
* @brief 根据引用获取类型
|
||||
* @param ctx 上下文指针
|
||||
* @param ref 类型引用
|
||||
* @return 类型指针(NULL表示无效引用)
|
||||
*/
|
||||
scc_ir_type_t *scc_ir_ctx_get_type(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_type_ref_t ref);
|
||||
|
||||
/**
|
||||
* @brief 根据引用获取节点
|
||||
* @param ctx 上下文指针
|
||||
* @param ref 节点引用
|
||||
* @return 节点指针(NULL表示无效引用)
|
||||
*/
|
||||
scc_ir_node_t *scc_ir_ctx_get_node(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_node_ref_t ref);
|
||||
|
||||
/**
|
||||
* @brief 根据引用获取基本块
|
||||
* @param ctx 上下文指针
|
||||
* @param ref 基本块引用
|
||||
* @return 基本块指针(NULL表示无效引用)
|
||||
*/
|
||||
scc_ir_bblock_t *scc_ir_ctx_get_bblock(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_bblock_ref_t ref);
|
||||
|
||||
/**
|
||||
* @brief 根据引用获取函数
|
||||
* @param ctx 上下文指针
|
||||
* @param ref 函数引用
|
||||
* @return 函数指针(NULL表示无效引用)
|
||||
*/
|
||||
scc_ir_func_t *scc_ir_ctx_get_func(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_func_ref_t ref);
|
||||
|
||||
// /**
|
||||
// * @brief 遍历所有类型
|
||||
// * @param ctx 上下文指针
|
||||
// * @param callback 回调函数
|
||||
// * @param userdata 用户数据
|
||||
// */
|
||||
// void scc_ir_ctx_foreach_type(scc_ir_cprog_ctx_t *ctx,
|
||||
// void (*callback)(scc_ir_type_ref_t ref,
|
||||
// scc_ir_type_t *type,
|
||||
// void *userdata),
|
||||
// void *userdata);
|
||||
|
||||
// /**
|
||||
// * @brief 遍历所有节点
|
||||
// */
|
||||
// void scc_ir_ctx_foreach_node(scc_ir_cprog_ctx_t *ctx,
|
||||
// void (*callback)(scc_ir_node_ref_t ref,
|
||||
// scc_ir_node_t *node,
|
||||
// void *userdata),
|
||||
// void *userdata);
|
||||
|
||||
// /**
|
||||
// * @brief 遍历所有基本块
|
||||
// */
|
||||
// void scc_ir_ctx_foreach_bblock(scc_ir_cprog_ctx_t *ctx,
|
||||
// void (*callback)(scc_ir_bblock_ref_t ref,
|
||||
// scc_ir_bblock_t *bblock,
|
||||
// void *userdata),
|
||||
// void *userdata);
|
||||
|
||||
// /**
|
||||
// * @brief 遍历所有函数
|
||||
// */
|
||||
// void scc_ir_ctx_foreach_func(scc_ir_cprog_ctx_t *ctx,
|
||||
// void (*callback)(scc_ir_func_ref_t ref,
|
||||
// scc_ir_func_t *func,
|
||||
// void *userdata),
|
||||
// void *userdata);
|
||||
|
||||
/**
|
||||
* @brief 获取内置i32类型
|
||||
* @param ctx 上下文指针
|
||||
* @return i32类型引用
|
||||
*/
|
||||
scc_ir_type_ref_t scc_ir_ctx_get_builtin_i32(scc_ir_cprog_ctx_t *ctx);
|
||||
|
||||
/**
|
||||
* @brief 获取内置零常量
|
||||
* @param ctx 上下文指针
|
||||
* @return 零常量节点引用
|
||||
*/
|
||||
scc_ir_node_ref_t scc_ir_ctx_get_builtin_zero(scc_ir_cprog_ctx_t *ctx);
|
||||
|
||||
/**
|
||||
* @brief 创建或获取i32常量
|
||||
* @param ctx 上下文指针
|
||||
* @param value 常量值
|
||||
* @return 常量节点引用
|
||||
*/
|
||||
scc_ir_node_ref_t scc_ir_ctx_get_i32_const(scc_ir_cprog_ctx_t *ctx, i32 value);
|
||||
|
||||
/**
|
||||
* @brief 创建或获取null常量
|
||||
* @param ctx 上下文指针
|
||||
* @param ptr_type 指针类型引用
|
||||
* @return null常量节点引用
|
||||
*/
|
||||
scc_ir_node_ref_t scc_ir_ctx_get_null_const(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_type_ref_t ptr_type);
|
||||
// 注册函数声明,若已存在则返回已有引用
|
||||
scc_ir_func_ref_t scc_ir_ctx_declare_func(scc_ir_ctx_t *ctx,
|
||||
scc_ir_type_ref_t type,
|
||||
const char *name);
|
||||
|
||||
#endif /* __SCC_IR_CTX_H__ */
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <scc_core.h>
|
||||
|
||||
#define SCC_IR_REF_NULL 0
|
||||
|
||||
typedef unsigned int ir_handle_t;
|
||||
typedef const char *scc_ir_label_t;
|
||||
|
||||
@@ -23,37 +25,34 @@ typedef ir_handle_t scc_ir_func_ref_t;
|
||||
typedef SCC_VEC(scc_ir_func_ref_t) scc_ir_func_ref_vec_t;
|
||||
|
||||
typedef enum scc_ir_type_tag {
|
||||
SCC_IR_TYPE_UNKNOWN,
|
||||
SCC_IR_TYPE_VOID,
|
||||
|
||||
SCC_IR_TYPE_I8,
|
||||
SCC_IR_TYPE_I16,
|
||||
SCC_IR_TYPE_I32,
|
||||
SCC_IR_TYPE_I64,
|
||||
SCC_IR_TYPE_I128,
|
||||
|
||||
SCC_IR_TYPE_U8,
|
||||
SCC_IR_TYPE_U16,
|
||||
SCC_IR_TYPE_U32,
|
||||
SCC_IR_TYPE_U64,
|
||||
SCC_IR_TYPE_U128,
|
||||
|
||||
SCC_IR_TYPE_F16,
|
||||
SCC_IR_TYPE_F32,
|
||||
SCC_IR_TYPE_F64,
|
||||
SCC_IR_TYPE_F128,
|
||||
SCC_IR_TYPE_unknown,
|
||||
SCC_IR_TYPE_void,
|
||||
SCC_IR_TYPE_i8,
|
||||
SCC_IR_TYPE_i16,
|
||||
SCC_IR_TYPE_i32,
|
||||
SCC_IR_TYPE_i64,
|
||||
SCC_IR_TYPE_i128,
|
||||
SCC_IR_TYPE_u8,
|
||||
SCC_IR_TYPE_u16,
|
||||
SCC_IR_TYPE_u32,
|
||||
SCC_IR_TYPE_u64,
|
||||
SCC_IR_TYPE_u128,
|
||||
SCC_IR_TYPE_f16,
|
||||
SCC_IR_TYPE_f32,
|
||||
SCC_IR_TYPE_f64,
|
||||
SCC_IR_TYPE_f128,
|
||||
|
||||
SCC_IR_TYPE_PTR,
|
||||
SCC_IR_TYPE_ARRAY,
|
||||
SCC_IR_TYPE_FUNC,
|
||||
SCC_IR_TYPE_STRUCT,
|
||||
SCC_IR_TYPE_VECTOR,
|
||||
SCC_IR_TYPE_UNION,
|
||||
SCC_IR_TYPE_VECTOR, // TODO SIMD
|
||||
} scc_ir_type_tag_t;
|
||||
|
||||
struct scc_ir_type {
|
||||
scc_ir_type_tag_t tag;
|
||||
int size; // 字节大小
|
||||
int align; // 对齐要求
|
||||
const char *name; // For Debug
|
||||
union {
|
||||
struct {
|
||||
scc_ir_type_ref_t base;
|
||||
@@ -62,6 +61,9 @@ struct scc_ir_type {
|
||||
struct {
|
||||
scc_ir_type_ref_t base;
|
||||
} pointer;
|
||||
struct {
|
||||
scc_ir_type_ref_vec_t elements;
|
||||
} aggregate;
|
||||
struct {
|
||||
scc_ir_type_ref_vec_t params;
|
||||
scc_ir_type_ref_t ret_type;
|
||||
@@ -144,28 +146,41 @@ typedef enum {
|
||||
SCC_IR_OP_SAR,
|
||||
} scc_ir_op_type_t;
|
||||
|
||||
typedef union {
|
||||
i8 int8;
|
||||
i16 int16;
|
||||
i32 int32;
|
||||
i64 int64;
|
||||
// TODO int128
|
||||
i8 int_any[16];
|
||||
} scc_ir_const_int_t;
|
||||
|
||||
typedef union {
|
||||
u8 uint8;
|
||||
u16 uint16;
|
||||
u32 uint32;
|
||||
u64 uint64;
|
||||
// TODO uint128;
|
||||
u8 uint_any[16];
|
||||
} scc_ir_const_uint_t;
|
||||
|
||||
typedef union {
|
||||
// f16 float16;
|
||||
f32 float32;
|
||||
f64 float64;
|
||||
// TODO float128;
|
||||
u8 float_any[16];
|
||||
} scc_ir_const_float_t;
|
||||
|
||||
struct scc_ir_node {
|
||||
scc_ir_type_ref_t type;
|
||||
scc_ir_label_t name;
|
||||
scc_ir_node_ref_vec_t used_by;
|
||||
scc_ir_node_tag_t tag;
|
||||
union {
|
||||
union {
|
||||
i8 int8;
|
||||
i16 int16;
|
||||
i32 int32;
|
||||
i64 int64;
|
||||
// TODO int128
|
||||
i8 int_any[16];
|
||||
} const_int;
|
||||
union {
|
||||
u8 uint8;
|
||||
u16 uint16;
|
||||
u32 uint32;
|
||||
u64 uint64;
|
||||
// TODO uint128;
|
||||
u8 uint_any[16];
|
||||
} const_uint;
|
||||
scc_ir_const_int_t const_int;
|
||||
scc_ir_const_uint_t const_uint;
|
||||
scc_ir_const_float_t const_float;
|
||||
// aggregate;
|
||||
struct {
|
||||
usize idx;
|
||||
@@ -216,10 +231,4 @@ struct scc_ir_node {
|
||||
} data;
|
||||
};
|
||||
|
||||
typedef struct scc_ir_cprog {
|
||||
scc_ir_node_ref_vec_t global_vals; /* 全局变量 */
|
||||
scc_ir_func_ref_vec_t func_defs; /* 所有函数定义 */
|
||||
scc_ir_func_ref_vec_t func_decls; /* 所有函数包括定义的声明 */
|
||||
} scc_ir_cprog_t;
|
||||
|
||||
#endif /* __SCC_IR_DEF_H__ */
|
||||
|
||||
@@ -1,20 +1,17 @@
|
||||
#ifndef __SCC_IR_DUMP_H__
|
||||
#define __SCC_IR_DUMP_H__
|
||||
|
||||
#include "ir_ctx.h"
|
||||
#include "ir_def.h"
|
||||
#include "ir_prog.h"
|
||||
#include <tree_dump.h>
|
||||
|
||||
typedef struct {
|
||||
scc_ir_cprog_ctx_t *ir_ctx;
|
||||
scc_ir_cprog_t *cprog;
|
||||
scc_tree_dump_ctx_t *dump_ctx;
|
||||
} scc_ir_dump_ctx_t;
|
||||
|
||||
void scc_ir_dump_ctx_init(scc_ir_dump_ctx_t *ctx,
|
||||
scc_tree_dump_ctx_t *tree_dump, scc_ir_cprog_t *cprog,
|
||||
scc_ir_cprog_ctx_t *ir_ctx);
|
||||
|
||||
scc_tree_dump_ctx_t *tree_dump,
|
||||
scc_ir_cprog_t *cprog);
|
||||
void scc_ir_dump_node(scc_ir_dump_ctx_t *ctx, scc_ir_node_ref_t node_ref);
|
||||
void scc_ir_dump_type(scc_ir_dump_ctx_t *ctx, scc_ir_type_ref_t type_ref);
|
||||
void scc_ir_dump_bblock(scc_ir_dump_ctx_t *ctx, scc_ir_bblock_ref_t bblock_ref);
|
||||
|
||||
52
libs/ir/include/ir_prog.h
Normal file
52
libs/ir/include/ir_prog.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#ifndef __SCC_IR_PROG_H__
|
||||
#define __SCC_IR_PROG_H__
|
||||
|
||||
#include "ir_def.h"
|
||||
#include <scc_utils.h>
|
||||
|
||||
typedef struct {
|
||||
unsigned int node_uid;
|
||||
unsigned int type_uid;
|
||||
unsigned int bblock_uid;
|
||||
unsigned int func_uid;
|
||||
SCC_VEC(scc_ir_node_t) nodes;
|
||||
SCC_VEC(scc_ir_type_t) types;
|
||||
SCC_VEC(scc_ir_bblock_t) bblocks;
|
||||
SCC_VEC(scc_ir_func_t) funcs;
|
||||
// UID -> ref index
|
||||
scc_hashtable_t uid2nodes;
|
||||
scc_hashtable_t uid2types;
|
||||
scc_hashtable_t uid2bblocks;
|
||||
scc_hashtable_t uid2funcs;
|
||||
} scc_ir_module_t;
|
||||
|
||||
void scc_ir_module_init(scc_ir_module_t *ctx);
|
||||
void scc_ir_module_drop(scc_ir_module_t *ctx);
|
||||
scc_ir_type_ref_t scc_ir_module_add_type(scc_ir_module_t *ctx,
|
||||
const scc_ir_type_t *type);
|
||||
scc_ir_node_ref_t scc_ir_module_add_node(scc_ir_module_t *ctx,
|
||||
const scc_ir_node_t *node);
|
||||
scc_ir_bblock_ref_t scc_ir_module_add_bblock(scc_ir_module_t *ctx,
|
||||
const scc_ir_bblock_t *bblock);
|
||||
scc_ir_func_ref_t scc_ir_module_add_func(scc_ir_module_t *ctx,
|
||||
const scc_ir_func_t *func);
|
||||
scc_ir_type_t *scc_ir_module_get_type(scc_ir_module_t *ctx,
|
||||
scc_ir_type_ref_t ref);
|
||||
scc_ir_node_t *scc_ir_module_get_node(scc_ir_module_t *ctx,
|
||||
scc_ir_node_ref_t ref);
|
||||
scc_ir_bblock_t *scc_ir_module_get_bblock(scc_ir_module_t *ctx,
|
||||
scc_ir_bblock_ref_t ref);
|
||||
scc_ir_func_t *scc_ir_module_get_func(scc_ir_module_t *ctx,
|
||||
scc_ir_func_ref_t ref);
|
||||
|
||||
typedef struct scc_ir_cprog {
|
||||
scc_ir_module_t module;
|
||||
scc_ir_node_ref_vec_t global_vals; /* 全局变量 */
|
||||
scc_ir_func_ref_vec_t func_defs; /* 所有函数定义 */
|
||||
scc_ir_func_ref_vec_t func_decls; /* 所有函数包括定义的声明 */
|
||||
} scc_ir_cprog_t;
|
||||
|
||||
void scc_ir_cprog_init(scc_ir_cprog_t *in);
|
||||
void scc_ir_cprog_drop(scc_ir_cprog_t *in);
|
||||
|
||||
#endif /* __SCC_IR_PROG_H__ */
|
||||
@@ -1,9 +1,15 @@
|
||||
#ifndef __SCC_IR_H__
|
||||
#define __SCC_IR_H__
|
||||
|
||||
#include "ir_builder.h"
|
||||
#include "ir_ctx.h"
|
||||
#include "ir_def.h"
|
||||
#include <scc_utils.h>
|
||||
#include "ir_prog.h"
|
||||
|
||||
void scc_ir_type_init(scc_ir_type_t *in, scc_ir_type_tag_t tag);
|
||||
void scc_ir_bblock_init(scc_ir_bblock_t *in, const char *label);
|
||||
void scc_ir_func_init(scc_ir_func_t *in, const char *name);
|
||||
|
||||
// node name can be null ptr
|
||||
void scc_ir_node_init(scc_ir_node_t *in, const char *name,
|
||||
scc_ir_node_tag_t tag);
|
||||
|
||||
#endif /* __SCC_IR_H__ */
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
#include <ir_builder.h>
|
||||
#include <ir_builtin.h>
|
||||
#include <ir_prog.h>
|
||||
|
||||
void scc_ir_builder_init(scc_ir_builder_t *builder) {
|
||||
#define GET_MODULE(builder) (&(builder->cprog->module))
|
||||
|
||||
void scc_ir_builder_init(scc_ir_builder_t *builder, scc_ir_cprog_t *cprog) {
|
||||
builder->current_bblock = SCC_IR_REF_NULL;
|
||||
builder->current_func = SCC_IR_REF_NULL;
|
||||
builder->cprog = cprog;
|
||||
|
||||
scc_ir_cprog_init(&builder->cprog);
|
||||
scc_ir_ctx_init(&builder->ctx);
|
||||
scc_ir_ctx_init(&builder->ctx, GET_MODULE(builder));
|
||||
}
|
||||
|
||||
void scc_ir_builder_drop(scc_ir_builder_t *builder) {
|
||||
scc_ir_cprog_drop(&builder->cprog);
|
||||
scc_ir_ctx_drop(&builder->ctx);
|
||||
}
|
||||
|
||||
scc_ir_func_ref_t scc_ir_builder_func(scc_ir_builder_t *builder,
|
||||
scc_ir_type_ref_t type_ref,
|
||||
const char *name) {
|
||||
scc_ir_func_t func = {
|
||||
.name = name,
|
||||
.type = type_ref,
|
||||
};
|
||||
scc_vec_init(func.params);
|
||||
scc_vec_init(func.bblocks);
|
||||
|
||||
scc_ir_func_ref_t func_ref = scc_ir_ctx_new_func(&builder->ctx, &func);
|
||||
scc_ir_func_ref_t func_ref =
|
||||
scc_ir_ctx_declare_func(&builder->ctx, type_ref, name);
|
||||
scc_vec_push(builder->cprog->func_decls, func_ref);
|
||||
return func_ref;
|
||||
}
|
||||
|
||||
scc_ir_type_ref_t scc_ir_builder_type(scc_ir_builder_t *builder,
|
||||
const scc_ir_type_t *type_desc) {
|
||||
return scc_ir_ctx_get_type(&builder->ctx, type_desc);
|
||||
}
|
||||
|
||||
void scc_ir_builder_begin_func(scc_ir_builder_t *builder,
|
||||
scc_ir_func_ref_t func_ref,
|
||||
const char **param_names) {
|
||||
// 创建函数并设置为当前函数
|
||||
builder->current_func = func_ref;
|
||||
|
||||
scc_ir_func_t *func_ptr = scc_ir_ctx_get_func(&builder->ctx, func_ref);
|
||||
scc_ir_func_t *func_ptr =
|
||||
scc_ir_module_get_func(GET_MODULE(builder), func_ref);
|
||||
scc_ir_type_t *func_type =
|
||||
scc_ir_ctx_get_type(&builder->ctx, func_ptr->type);
|
||||
scc_ir_module_get_type(GET_MODULE(builder), func_ptr->type);
|
||||
|
||||
if (func_type == null || func_type->tag != SCC_IR_TYPE_FUNC) {
|
||||
LOG_ERROR("Invalid function type");
|
||||
@@ -66,7 +68,7 @@ void scc_ir_builder_begin_func(scc_ir_builder_t *builder,
|
||||
scc_vec_init(param_node.used_by);
|
||||
|
||||
scc_ir_node_ref_t param_ref =
|
||||
scc_ir_ctx_new_node(&builder->ctx, ¶m_node);
|
||||
scc_ir_module_add_node(GET_MODULE(builder), ¶m_node);
|
||||
scc_vec_push(func_ptr->params, param_ref);
|
||||
}
|
||||
|
||||
@@ -75,15 +77,16 @@ void scc_ir_builder_begin_func(scc_ir_builder_t *builder,
|
||||
|
||||
void scc_ir_builder_end_func(scc_ir_builder_t *builder) {
|
||||
scc_ir_func_t *func_ptr =
|
||||
scc_ir_ctx_get_func(&builder->ctx, builder->current_func);
|
||||
scc_ir_module_get_func(GET_MODULE(builder), builder->current_func);
|
||||
if (func_ptr == null) {
|
||||
LOG_FATAL("Invalid function reference");
|
||||
return;
|
||||
}
|
||||
if (scc_vec_size(func_ptr->bblocks) == 0) {
|
||||
scc_vec_push(builder->cprog.func_decls, builder->current_func);
|
||||
// FIXME
|
||||
scc_vec_push(builder->cprog->func_decls, builder->current_func);
|
||||
} else {
|
||||
scc_vec_push(builder->cprog.func_defs, builder->current_func);
|
||||
scc_vec_push(builder->cprog->func_defs, builder->current_func);
|
||||
}
|
||||
builder->current_func = 0;
|
||||
}
|
||||
@@ -100,10 +103,10 @@ scc_ir_bblock_ref_t scc_ir_builder_bblock(scc_ir_builder_t *builder,
|
||||
}
|
||||
scc_vec_init(bblock.instrs);
|
||||
scc_ir_bblock_ref_t bblock_ref =
|
||||
scc_ir_ctx_new_bblock(&builder->ctx, &bblock);
|
||||
scc_ir_module_add_bblock(GET_MODULE(builder), &bblock);
|
||||
|
||||
scc_ir_func_t *current_func =
|
||||
scc_ir_ctx_get_func(&builder->ctx, builder->current_func);
|
||||
scc_ir_module_get_func(GET_MODULE(builder), builder->current_func);
|
||||
if (current_func) {
|
||||
scc_vec_push(current_func->bblocks, bblock_ref);
|
||||
}
|
||||
@@ -129,7 +132,7 @@ void scc_ir_builder_set_current_bblock(scc_ir_builder_t *builder,
|
||||
static void scc_ir_builder_add_instr(scc_ir_builder_t *builder,
|
||||
scc_ir_node_ref_t node) {
|
||||
scc_ir_bblock_t *current_bblock =
|
||||
scc_ir_ctx_get_bblock(&builder->ctx, builder->current_bblock);
|
||||
scc_ir_module_get_bblock(GET_MODULE(builder), builder->current_bblock);
|
||||
if (current_bblock) {
|
||||
scc_vec_push(current_bblock->instrs, node);
|
||||
} else {
|
||||
@@ -142,13 +145,13 @@ scc_ir_node_ref_t scc_ir_builder_alloca(scc_ir_builder_t *builder,
|
||||
const char *name) {
|
||||
scc_ir_node_t alloc_node = {0};
|
||||
alloc_node.tag = SCC_IR_NODE_ALLOC;
|
||||
alloc_node.type = scc_ir_ctx_new_type(
|
||||
&builder->ctx,
|
||||
alloc_node.type = scc_ir_module_add_type(
|
||||
GET_MODULE(builder),
|
||||
&(scc_ir_type_t){.tag = SCC_IR_TYPE_PTR, .data.pointer.base = type});
|
||||
alloc_node.name = name;
|
||||
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_ctx_new_node(&builder->ctx, &alloc_node);
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &alloc_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -165,7 +168,8 @@ scc_ir_node_ref_t scc_ir_builder_func_arg_ref(scc_ir_builder_t *builder,
|
||||
node.name = name;
|
||||
node.data.arg_ref.idx = arg_idx;
|
||||
|
||||
scc_ir_node_ref_t node_ref = scc_ir_ctx_new_node(&builder->ctx, &node);
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &node);
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
return node_ref;
|
||||
@@ -178,16 +182,18 @@ scc_ir_node_ref_t scc_ir_builder_load(scc_ir_builder_t *builder,
|
||||
load_node.data.load.target = target;
|
||||
|
||||
// 设置类型为指针指向的类型
|
||||
scc_ir_node_t *ptr_node = scc_ir_ctx_get_node(&builder->ctx, target);
|
||||
scc_ir_node_t *ptr_node =
|
||||
scc_ir_module_get_node(GET_MODULE(builder), target);
|
||||
if (ptr_node) {
|
||||
scc_ir_type_t *ptr_type =
|
||||
scc_ir_ctx_get_type(&builder->ctx, ptr_node->type);
|
||||
scc_ir_module_get_type(GET_MODULE(builder), ptr_node->type);
|
||||
if (ptr_type && ptr_type->tag == SCC_IR_TYPE_PTR) {
|
||||
load_node.type = ptr_type->data.pointer.base;
|
||||
}
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t node_ref = scc_ir_ctx_new_node(&builder->ctx, &load_node);
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &load_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -204,7 +210,7 @@ scc_ir_node_ref_t scc_ir_builder_store(scc_ir_builder_t *builder,
|
||||
store_node.data.store.value = value;
|
||||
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_ctx_new_node(&builder->ctx, &store_node);
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &store_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -221,13 +227,14 @@ scc_ir_node_ref_t scc_ir_builder_get_ptr(scc_ir_builder_t *builder,
|
||||
get_ptr_node.data.get_ptr.index = index;
|
||||
|
||||
// 类型应与源地址相同(都是指针)
|
||||
scc_ir_node_t *src_node = scc_ir_ctx_get_node(&builder->ctx, target);
|
||||
scc_ir_node_t *src_node =
|
||||
scc_ir_module_get_node(GET_MODULE(builder), target);
|
||||
if (src_node) {
|
||||
get_ptr_node.type = src_node->type;
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_ctx_new_node(&builder->ctx, &get_ptr_node);
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &get_ptr_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -246,13 +253,13 @@ scc_ir_node_ref_t scc_ir_builder_binop(scc_ir_builder_t *builder,
|
||||
binop_node.data.op.rhs = rhs;
|
||||
|
||||
// 类型通常与操作数相同(对于算术运算)
|
||||
scc_ir_node_t *lhs_node = scc_ir_ctx_get_node(&builder->ctx, lhs);
|
||||
scc_ir_node_t *lhs_node = scc_ir_module_get_node(GET_MODULE(builder), lhs);
|
||||
if (lhs_node) {
|
||||
binop_node.type = lhs_node->type;
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_ctx_new_node(&builder->ctx, &binop_node);
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &binop_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -270,9 +277,11 @@ scc_ir_node_ref_t scc_ir_builder_cmp(scc_ir_builder_t *builder,
|
||||
cmp_node.data.op.rhs = rhs;
|
||||
|
||||
// 比较操作的结果通常是布尔值
|
||||
cmp_node.type = scc_ir_ctx_get_builtin_i32(&builder->ctx);
|
||||
cmp_node.type =
|
||||
0; // FIXME scc_ir_module_get_builtin_i32(GET_MODULE(builder));
|
||||
|
||||
scc_ir_node_ref_t node_ref = scc_ir_ctx_new_node(&builder->ctx, &cmp_node);
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &cmp_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -286,7 +295,8 @@ scc_ir_node_ref_t scc_ir_builder_jump(scc_ir_builder_t *builder,
|
||||
jump_node.tag = SCC_IR_NODE_JUMP;
|
||||
jump_node.data.jump.target_bblock = target;
|
||||
|
||||
scc_ir_node_ref_t node_ref = scc_ir_ctx_new_node(&builder->ctx, &jump_node);
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &jump_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -305,7 +315,7 @@ scc_ir_node_ref_t scc_ir_builder_branch(scc_ir_builder_t *builder,
|
||||
branch_node.data.branch.false_bblock = false_target;
|
||||
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_ctx_new_node(&builder->ctx, &branch_node);
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &branch_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -327,16 +337,18 @@ scc_ir_node_ref_t scc_ir_builder_call(scc_ir_builder_t *builder,
|
||||
}
|
||||
|
||||
// 设置返回类型为被调用函数的返回类型
|
||||
scc_ir_func_t *callee_func = scc_ir_ctx_get_func(&builder->ctx, callee);
|
||||
scc_ir_func_t *callee_func =
|
||||
scc_ir_module_get_func(GET_MODULE(builder), callee);
|
||||
if (callee_func) {
|
||||
scc_ir_type_t *func_type =
|
||||
scc_ir_ctx_get_type(&builder->ctx, callee_func->type);
|
||||
scc_ir_module_get_type(GET_MODULE(builder), callee_func->type);
|
||||
if (func_type && func_type->tag == SCC_IR_TYPE_FUNC) {
|
||||
call_node.type = func_type->data.function.ret_type;
|
||||
}
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t node_ref = scc_ir_ctx_new_node(&builder->ctx, &call_node);
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &call_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -350,7 +362,8 @@ scc_ir_node_ref_t scc_ir_builder_ret(scc_ir_builder_t *builder,
|
||||
ret_node.tag = SCC_IR_NODE_RET;
|
||||
ret_node.data.ret.ret_val = value;
|
||||
|
||||
scc_ir_node_ref_t node_ref = scc_ir_ctx_new_node(&builder->ctx, &ret_node);
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &ret_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
@@ -363,7 +376,8 @@ scc_ir_node_ref_t scc_ir_builder_ret_void(scc_ir_builder_t *builder) {
|
||||
ret_node.tag = SCC_IR_NODE_RET;
|
||||
ret_node.data.ret.ret_val = 0; // 无返回值
|
||||
|
||||
scc_ir_node_ref_t node_ref = scc_ir_ctx_new_node(&builder->ctx, &ret_node);
|
||||
scc_ir_node_ref_t node_ref =
|
||||
scc_ir_module_add_node(GET_MODULE(builder), &ret_node);
|
||||
|
||||
// 添加到当前基本块
|
||||
scc_ir_builder_add_instr(builder, node_ref);
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
#include <ir_builtin.h>
|
||||
|
||||
scc_ir_type_t scc_ir_builtin_i32 = {
|
||||
.tag = SCC_IR_TYPE_I32,
|
||||
};
|
||||
|
||||
scc_ir_node_t scc_ir_builtin_zero = {
|
||||
.tag = SCC_IR_NODE_CONST_INT,
|
||||
.data.const_int.int_any = {0},
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
#include "ir_ctx.h"
|
||||
#include "ir_builtin.h"
|
||||
#include <ir_ctx.h>
|
||||
|
||||
/**
|
||||
* @brief 哈希混合函数(类似Rust的hash combine)
|
||||
@@ -12,30 +11,27 @@ static inline u32 scc_hash_mix(u32 seed, u32 value) {
|
||||
return (seed ^ value) * 16777619u;
|
||||
}
|
||||
|
||||
static u32 hash_key(const void *key) { return (u32)(usize)key; }
|
||||
static int cmp_key(const void *key1, const void *key2) {
|
||||
return (u32)(usize)key1 != (u32)(usize)key2;
|
||||
}
|
||||
static u32 hash_type(const scc_ir_type_t *key) {
|
||||
static u32 hash_type(const void *_key) {
|
||||
const scc_ir_type_t *key = _key;
|
||||
// 初始哈希:tag
|
||||
u32 hash = (u32)key->tag;
|
||||
|
||||
switch (key->tag) {
|
||||
case SCC_IR_TYPE_VOID:
|
||||
case SCC_IR_TYPE_U8:
|
||||
case SCC_IR_TYPE_U16:
|
||||
case SCC_IR_TYPE_U32:
|
||||
case SCC_IR_TYPE_U64:
|
||||
case SCC_IR_TYPE_U128:
|
||||
case SCC_IR_TYPE_I8:
|
||||
case SCC_IR_TYPE_I16:
|
||||
case SCC_IR_TYPE_I32:
|
||||
case SCC_IR_TYPE_I64:
|
||||
case SCC_IR_TYPE_I128:
|
||||
case SCC_IR_TYPE_F16:
|
||||
case SCC_IR_TYPE_F32:
|
||||
case SCC_IR_TYPE_F64:
|
||||
case SCC_IR_TYPE_F128:
|
||||
case SCC_IR_TYPE_void:
|
||||
case SCC_IR_TYPE_u8:
|
||||
case SCC_IR_TYPE_u16:
|
||||
case SCC_IR_TYPE_u32:
|
||||
case SCC_IR_TYPE_u64:
|
||||
case SCC_IR_TYPE_u128:
|
||||
case SCC_IR_TYPE_i8:
|
||||
case SCC_IR_TYPE_i16:
|
||||
case SCC_IR_TYPE_i32:
|
||||
case SCC_IR_TYPE_i64:
|
||||
case SCC_IR_TYPE_i128:
|
||||
case SCC_IR_TYPE_f16:
|
||||
case SCC_IR_TYPE_f32:
|
||||
case SCC_IR_TYPE_f64:
|
||||
case SCC_IR_TYPE_f128:
|
||||
// 基本类型,只有tag
|
||||
break;
|
||||
|
||||
@@ -66,28 +62,29 @@ static u32 hash_type(const scc_ir_type_t *key) {
|
||||
|
||||
return hash;
|
||||
}
|
||||
static int cmp_type(const scc_ir_type_t *key1, const scc_ir_type_t *key2) {
|
||||
static int cmp_type(const void *_key1, const void *_key2) {
|
||||
const scc_ir_type_t *key1 = _key1, *key2 = _key2;
|
||||
// tag不同
|
||||
if (key1->tag != key2->tag) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (key1->tag) {
|
||||
case SCC_IR_TYPE_VOID:
|
||||
case SCC_IR_TYPE_U8:
|
||||
case SCC_IR_TYPE_U16:
|
||||
case SCC_IR_TYPE_U32:
|
||||
case SCC_IR_TYPE_U64:
|
||||
case SCC_IR_TYPE_U128:
|
||||
case SCC_IR_TYPE_I8:
|
||||
case SCC_IR_TYPE_I16:
|
||||
case SCC_IR_TYPE_I32:
|
||||
case SCC_IR_TYPE_I64:
|
||||
case SCC_IR_TYPE_I128:
|
||||
case SCC_IR_TYPE_F16:
|
||||
case SCC_IR_TYPE_F32:
|
||||
case SCC_IR_TYPE_F64:
|
||||
case SCC_IR_TYPE_F128:
|
||||
case SCC_IR_TYPE_void:
|
||||
case SCC_IR_TYPE_u8:
|
||||
case SCC_IR_TYPE_u16:
|
||||
case SCC_IR_TYPE_u32:
|
||||
case SCC_IR_TYPE_u64:
|
||||
case SCC_IR_TYPE_u128:
|
||||
case SCC_IR_TYPE_i8:
|
||||
case SCC_IR_TYPE_i16:
|
||||
case SCC_IR_TYPE_i32:
|
||||
case SCC_IR_TYPE_i64:
|
||||
case SCC_IR_TYPE_i128:
|
||||
case SCC_IR_TYPE_f16:
|
||||
case SCC_IR_TYPE_f32:
|
||||
case SCC_IR_TYPE_f64:
|
||||
case SCC_IR_TYPE_f128:
|
||||
return 0; // 基本类型,tag相同即可
|
||||
case SCC_IR_TYPE_PTR:
|
||||
return key1->data.pointer.base != key2->data.pointer.base;
|
||||
@@ -121,213 +118,61 @@ static int cmp_type(const scc_ir_type_t *key1, const scc_ir_type_t *key2) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void scc_ir_ctx_init(scc_ir_cprog_ctx_t *ctx) {
|
||||
// 初始化向量
|
||||
scc_vec_init(ctx->nodes);
|
||||
scc_vec_init(ctx->types);
|
||||
scc_vec_init(ctx->bblocks);
|
||||
scc_vec_init(ctx->funcs);
|
||||
|
||||
// 初始化哈希表
|
||||
scc_hashtable_init(&ctx->uid2nodes, hash_key, cmp_key);
|
||||
scc_hashtable_init(&ctx->uid2types, hash_key, cmp_key);
|
||||
scc_hashtable_init(&ctx->uid2bblocks, hash_key, cmp_key);
|
||||
scc_hashtable_init(&ctx->uid2funcs, hash_key, cmp_key);
|
||||
|
||||
scc_hashtable_init(&ctx->type_uniquing,
|
||||
(scc_hashtable_hash_func_t)hash_type,
|
||||
(scc_hashtable_equal_func_t)cmp_type);
|
||||
|
||||
// 预留UID 0 作为无效引用
|
||||
ctx->node_uid = 1;
|
||||
ctx->type_uid = 1;
|
||||
ctx->bblock_uid = 1;
|
||||
ctx->func_uid = 1;
|
||||
void scc_ir_ctx_init(scc_ir_ctx_t *ctx, scc_ir_module_t *module) {
|
||||
ctx->module = module;
|
||||
scc_hashtable_init(&ctx->type_uniquing, hash_type, cmp_type);
|
||||
// scc_hashtable_init(&ctx->const_pool, /* 常量哈希函数 */,
|
||||
// /* 常量比较函数 */);
|
||||
scc_hashtable_init(&ctx->func_decl_set,
|
||||
(scc_hashtable_hash_func_t)scc_strhash32,
|
||||
(scc_hashtable_equal_func_t)scc_strcmp);
|
||||
}
|
||||
|
||||
void scc_ir_ctx_drop(scc_ir_cprog_ctx_t *ctx) {
|
||||
// 释放所有实体的内部内存
|
||||
for (usize i = 0; i < ctx->nodes.size; i++) {
|
||||
scc_ir_node_t *node = &ctx->nodes.data[i];
|
||||
scc_vec_free(node->used_by);
|
||||
if (node->tag == SCC_IR_NODE_CALL) {
|
||||
scc_vec_free(node->data.call.args);
|
||||
}
|
||||
void scc_ir_ctx_drop(scc_ir_ctx_t *ctx) {
|
||||
scc_hashtable_drop(&ctx->type_uniquing);
|
||||
// scc_hashtable_drop(&ctx->const_pool);
|
||||
scc_hashtable_drop(&ctx->func_decl_set);
|
||||
}
|
||||
|
||||
scc_ir_type_ref_t scc_ir_ctx_get_type(scc_ir_ctx_t *ctx,
|
||||
const scc_ir_type_t *type_desc) {
|
||||
// 先查哈希表
|
||||
void *found = scc_hashtable_get(&ctx->type_uniquing, (void *)type_desc);
|
||||
if (found) {
|
||||
return (scc_ir_type_ref_t)(usize)found;
|
||||
}
|
||||
|
||||
for (usize i = 0; i < ctx->types.size; i++) {
|
||||
scc_ir_type_t *type = &ctx->types.data[i];
|
||||
if (type->tag == SCC_IR_TYPE_FUNC) {
|
||||
scc_vec_free(type->data.function.params);
|
||||
}
|
||||
// 不存在,添加新类型
|
||||
scc_ir_type_ref_t new_ref = scc_ir_module_add_type(ctx->module, type_desc);
|
||||
scc_hashtable_set(&ctx->type_uniquing, (void *)type_desc,
|
||||
(void *)(usize)new_ref);
|
||||
return new_ref;
|
||||
}
|
||||
|
||||
// scc_ir_node_ref_t scc_ir_ctx_get_const_int(scc_ir_ctx_t *ctx,
|
||||
// scc_ir_type_ref_t type, i64 value)
|
||||
// {
|
||||
// return scc_ir_node_ref_t();
|
||||
// }
|
||||
|
||||
scc_ir_func_ref_t scc_ir_ctx_declare_func(scc_ir_ctx_t *ctx,
|
||||
scc_ir_type_ref_t type,
|
||||
const char *name) {
|
||||
// 检查是否已声明
|
||||
void *found = scc_hashtable_get(&ctx->func_decl_set, (void *)name);
|
||||
if (found) {
|
||||
return (scc_ir_func_ref_t)(usize)found;
|
||||
}
|
||||
|
||||
for (usize i = 0; i < ctx->bblocks.size; i++) {
|
||||
scc_ir_bblock_t *bblock = &ctx->bblocks.data[i];
|
||||
scc_vec_free(bblock->instrs);
|
||||
}
|
||||
|
||||
for (usize i = 0; i < ctx->funcs.size; i++) {
|
||||
scc_ir_func_t *func = &ctx->funcs.data[i];
|
||||
scc_vec_free(func->params);
|
||||
scc_vec_free(func->bblocks);
|
||||
}
|
||||
|
||||
// 释放向量
|
||||
scc_vec_free(ctx->nodes);
|
||||
scc_vec_free(ctx->types);
|
||||
scc_vec_free(ctx->bblocks);
|
||||
scc_vec_free(ctx->funcs);
|
||||
|
||||
// 释放哈希表
|
||||
scc_hashtable_drop(&ctx->uid2nodes);
|
||||
scc_hashtable_drop(&ctx->uid2types);
|
||||
scc_hashtable_drop(&ctx->uid2bblocks);
|
||||
scc_hashtable_drop(&ctx->uid2funcs);
|
||||
}
|
||||
|
||||
void scc_ir_ctx_reset(scc_ir_cprog_ctx_t *ctx) {
|
||||
// 先销毁再重新初始化
|
||||
scc_ir_ctx_drop(ctx);
|
||||
scc_ir_ctx_init(ctx);
|
||||
}
|
||||
|
||||
// 辅助宏:创建实体并添加到哈希表
|
||||
#define CREATE_ENTITY(ctx, vec, uid, data, hashtable) \
|
||||
do { \
|
||||
/* 分配新UID */ \
|
||||
unsigned new_uid = (ctx)->uid++; \
|
||||
/* 添加到向量 */ \
|
||||
scc_vec_push((vec), *(data)); \
|
||||
/* 添加到哈希表 */ \
|
||||
scc_hashtable_set(&(ctx)->hashtable, (const void *)(usize)new_uid, \
|
||||
(void *)(usize)(scc_vec_size(vec) - 1)); \
|
||||
return new_uid; \
|
||||
} while (0)
|
||||
|
||||
scc_ir_type_ref_t scc_ir_ctx_new_type(scc_ir_cprog_ctx_t *ctx,
|
||||
const scc_ir_type_t *type) {
|
||||
// 首先检查去重表
|
||||
void *existing = scc_hashtable_get(&ctx->type_uniquing, type);
|
||||
if (existing) {
|
||||
return (scc_ir_type_ref_t)(uintptr_t)existing;
|
||||
}
|
||||
|
||||
CREATE_ENTITY(ctx, ctx->types, type_uid, type, uid2types);
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t scc_ir_ctx_new_node(scc_ir_cprog_ctx_t *ctx,
|
||||
const scc_ir_node_t *node) {
|
||||
CREATE_ENTITY(ctx, ctx->nodes, node_uid, node, uid2nodes);
|
||||
}
|
||||
|
||||
scc_ir_bblock_ref_t scc_ir_ctx_new_bblock(scc_ir_cprog_ctx_t *ctx,
|
||||
const scc_ir_bblock_t *bblock) {
|
||||
CREATE_ENTITY(ctx, ctx->bblocks, bblock_uid, bblock, uid2bblocks);
|
||||
}
|
||||
|
||||
scc_ir_func_ref_t scc_ir_ctx_new_func(scc_ir_cprog_ctx_t *ctx,
|
||||
const scc_ir_func_t *func) {
|
||||
CREATE_ENTITY(ctx, ctx->funcs, func_uid, func, uid2funcs);
|
||||
}
|
||||
|
||||
#undef CREATE_ENTITY
|
||||
|
||||
// 辅助宏:从哈希表获取索引
|
||||
#define GET_ENTITY_INDEX(ctx, ref, hashtable) \
|
||||
((usize)scc_hashtable_get(&(ctx)->hashtable, (void *)(usize)ref))
|
||||
|
||||
scc_ir_type_t *scc_ir_ctx_get_type(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_type_ref_t ref) {
|
||||
if (ref == 0)
|
||||
return null;
|
||||
usize idx = GET_ENTITY_INDEX(ctx, ref, uid2types);
|
||||
if (idx >= ctx->types.size)
|
||||
return null;
|
||||
return &ctx->types.data[idx];
|
||||
}
|
||||
|
||||
scc_ir_node_t *scc_ir_ctx_get_node(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_node_ref_t ref) {
|
||||
if (ref == 0)
|
||||
return null;
|
||||
usize idx = GET_ENTITY_INDEX(ctx, ref, uid2nodes);
|
||||
if (idx >= ctx->nodes.size)
|
||||
return null;
|
||||
return &ctx->nodes.data[idx];
|
||||
}
|
||||
|
||||
scc_ir_bblock_t *scc_ir_ctx_get_bblock(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_bblock_ref_t ref) {
|
||||
if (ref == 0)
|
||||
return null;
|
||||
usize idx = GET_ENTITY_INDEX(ctx, ref, uid2bblocks);
|
||||
if (idx >= ctx->bblocks.size)
|
||||
return null;
|
||||
return &ctx->bblocks.data[idx];
|
||||
}
|
||||
|
||||
scc_ir_func_t *scc_ir_ctx_get_func(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_func_ref_t ref) {
|
||||
if (ref == 0)
|
||||
return null;
|
||||
usize idx = GET_ENTITY_INDEX(ctx, ref, uid2funcs);
|
||||
if (idx >= ctx->funcs.size)
|
||||
return null;
|
||||
return &ctx->funcs.data[idx];
|
||||
}
|
||||
|
||||
#undef GET_ENTITY_INDEX
|
||||
|
||||
// // 内置类型和常量缓存
|
||||
// static scc_ir_type_ref_t cached_i32_type = 0;
|
||||
// static scc_ir_node_ref_t cached_zero_const = 0;
|
||||
|
||||
scc_ir_type_ref_t scc_ir_ctx_get_builtin_i32(scc_ir_cprog_ctx_t *ctx) {
|
||||
scc_ir_type_ref_t cached_i32_type = 0;
|
||||
if (cached_i32_type == 0) {
|
||||
scc_ir_type_t i32_type = {.tag = SCC_IR_TYPE_I32};
|
||||
cached_i32_type = scc_ir_ctx_new_type(ctx, &i32_type);
|
||||
}
|
||||
return cached_i32_type;
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t scc_ir_ctx_get_builtin_zero(scc_ir_cprog_ctx_t *ctx) {
|
||||
scc_ir_node_ref_t cached_zero_const = 0;
|
||||
if (cached_zero_const == 0) {
|
||||
scc_ir_node_t zero_node = {.tag = SCC_IR_NODE_CONST_INT,
|
||||
.type = scc_ir_ctx_get_builtin_i32(ctx),
|
||||
.name = "zero",
|
||||
.data.const_int.int32 = 0};
|
||||
cached_zero_const = scc_ir_ctx_new_node(ctx, &zero_node);
|
||||
}
|
||||
return cached_zero_const;
|
||||
}
|
||||
|
||||
// 常量池(简化版)
|
||||
typedef struct {
|
||||
i32 value;
|
||||
scc_ir_node_ref_t ref;
|
||||
} i32_const_entry_t;
|
||||
|
||||
scc_ir_node_ref_t scc_ir_ctx_get_i32_const(scc_ir_cprog_ctx_t *ctx, i32 value) {
|
||||
// 如果是0,使用内置zero
|
||||
if (value == 0) {
|
||||
return scc_ir_ctx_get_builtin_zero(ctx);
|
||||
}
|
||||
|
||||
// TODO: 实现常量池哈希表
|
||||
// 这里简化实现,每次都创建新常量
|
||||
scc_ir_node_t const_node = {.tag = SCC_IR_NODE_CONST_INT,
|
||||
.type = scc_ir_ctx_get_builtin_i32(ctx),
|
||||
.data.const_int.int32 = value};
|
||||
|
||||
const_node.name = null;
|
||||
|
||||
return scc_ir_ctx_new_node(ctx, &const_node);
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t scc_ir_ctx_get_null_const(scc_ir_cprog_ctx_t *ctx,
|
||||
scc_ir_type_ref_t ptr_type) {
|
||||
return 1;
|
||||
// 创建新函数
|
||||
scc_ir_func_t func = {
|
||||
.name = name,
|
||||
.type = type,
|
||||
};
|
||||
scc_vec_init(func.params);
|
||||
scc_vec_init(func.bblocks);
|
||||
scc_ir_func_ref_t new_ref = scc_ir_module_add_func(ctx->module, &func);
|
||||
scc_hashtable_set(&ctx->func_decl_set, (void *)name,
|
||||
(void *)(usize)new_ref);
|
||||
return new_ref;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include <ir_ctx.h>
|
||||
#include <ir_dump.h>
|
||||
#include <ir_prog.h>
|
||||
|
||||
#define GET_MODULE(ctx) (&(ctx->cprog->module))
|
||||
|
||||
#define PRINT_VALUE(ctx, fmt, value) \
|
||||
SCC_TREE_DUMP_PRINT_PURE(ctx, ctx->value_color, fmt, value)
|
||||
@@ -66,14 +68,14 @@ static const char *get_op_str(scc_ir_op_type_t op) {
|
||||
// 获取类型标签字符串
|
||||
static const char *get_type_tag_str(scc_ir_type_tag_t tag) {
|
||||
static const char *type_tags[] = {
|
||||
[SCC_IR_TYPE_VOID] = "void", [SCC_IR_TYPE_U8] = "u8",
|
||||
[SCC_IR_TYPE_U16] = "u16", [SCC_IR_TYPE_U32] = "u32",
|
||||
[SCC_IR_TYPE_U64] = "u64", [SCC_IR_TYPE_U128] = "u128",
|
||||
[SCC_IR_TYPE_I8] = "i8", [SCC_IR_TYPE_I16] = "i16",
|
||||
[SCC_IR_TYPE_I32] = "i32", [SCC_IR_TYPE_I64] = "i64",
|
||||
[SCC_IR_TYPE_I128] = "i128", [SCC_IR_TYPE_F16] = "f16",
|
||||
[SCC_IR_TYPE_F32] = "f32", [SCC_IR_TYPE_F64] = "f64",
|
||||
[SCC_IR_TYPE_F128] = "f128", [SCC_IR_TYPE_PTR] = "ptr",
|
||||
[SCC_IR_TYPE_void] = "void", [SCC_IR_TYPE_u8] = "u8",
|
||||
[SCC_IR_TYPE_u16] = "u16", [SCC_IR_TYPE_u32] = "u32",
|
||||
[SCC_IR_TYPE_u64] = "u64", [SCC_IR_TYPE_u128] = "u128",
|
||||
[SCC_IR_TYPE_i8] = "i8", [SCC_IR_TYPE_i16] = "i16",
|
||||
[SCC_IR_TYPE_i32] = "i32", [SCC_IR_TYPE_i64] = "i64",
|
||||
[SCC_IR_TYPE_i128] = "i128", [SCC_IR_TYPE_f16] = "f16",
|
||||
[SCC_IR_TYPE_f32] = "f32", [SCC_IR_TYPE_f64] = "f64",
|
||||
[SCC_IR_TYPE_f128] = "f128", [SCC_IR_TYPE_PTR] = "ptr",
|
||||
[SCC_IR_TYPE_ARRAY] = "array", [SCC_IR_TYPE_FUNC] = "func",
|
||||
[SCC_IR_TYPE_STRUCT] = "struct", [SCC_IR_TYPE_VECTOR] = "vector",
|
||||
};
|
||||
@@ -176,8 +178,8 @@ static void dump_branch_node(scc_ir_dump_ctx_t *ctx,
|
||||
|
||||
// 输出真分支块
|
||||
if (node->data.branch.true_bblock) {
|
||||
scc_ir_bblock_t *true_bblock =
|
||||
scc_ir_ctx_get_bblock(ctx->ir_ctx, node->data.branch.true_bblock);
|
||||
scc_ir_bblock_t *true_bblock = scc_ir_module_get_bblock(
|
||||
GET_MODULE(ctx), node->data.branch.true_bblock);
|
||||
if (true_bblock) {
|
||||
scc_tree_print_indent(ctx->dump_ctx);
|
||||
PRINT_NODE(ctx->dump_ctx, "TrueBlock: ");
|
||||
@@ -189,8 +191,8 @@ static void dump_branch_node(scc_ir_dump_ctx_t *ctx,
|
||||
|
||||
// 输出假分支块
|
||||
if (node->data.branch.false_bblock) {
|
||||
scc_ir_bblock_t *false_bblock =
|
||||
scc_ir_ctx_get_bblock(ctx->ir_ctx, node->data.branch.false_bblock);
|
||||
scc_ir_bblock_t *false_bblock = scc_ir_module_get_bblock(
|
||||
GET_MODULE(ctx), node->data.branch.false_bblock);
|
||||
if (false_bblock) {
|
||||
scc_tree_print_indent(ctx->dump_ctx);
|
||||
PRINT_NODE(ctx->dump_ctx, "FalseBlock: ");
|
||||
@@ -205,8 +207,8 @@ static void dump_branch_node(scc_ir_dump_ctx_t *ctx,
|
||||
static void dump_jump_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||||
// PRINT_NODE(ctx->dump_ctx, "jump");
|
||||
if (node->data.jump.target_bblock) {
|
||||
scc_ir_bblock_t *target_bblock =
|
||||
scc_ir_ctx_get_bblock(ctx->ir_ctx, node->data.jump.target_bblock);
|
||||
scc_ir_bblock_t *target_bblock = scc_ir_module_get_bblock(
|
||||
GET_MODULE(ctx), node->data.jump.target_bblock);
|
||||
if (target_bblock) {
|
||||
scc_tree_dump_printf(ctx->dump_ctx, "to '%s'",
|
||||
target_bblock->label ? target_bblock->label
|
||||
@@ -224,7 +226,7 @@ static void dump_call_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||||
// PRINT_NODE(ctx->dump_ctx, "call");
|
||||
if (node->data.call.callee) {
|
||||
scc_ir_func_t *callee =
|
||||
scc_ir_ctx_get_func(ctx->ir_ctx, node->data.call.callee);
|
||||
scc_ir_module_get_func(GET_MODULE(ctx), node->data.call.callee);
|
||||
if (callee) {
|
||||
scc_tree_dump_printf(ctx->dump_ctx, "func='%s'",
|
||||
callee->name ? callee->name : "<unnamed>");
|
||||
@@ -260,15 +262,14 @@ static void dump_ret_node(scc_ir_dump_ctx_t *ctx, const scc_ir_node_t *node) {
|
||||
}
|
||||
|
||||
void scc_ir_dump_ctx_init(scc_ir_dump_ctx_t *ctx,
|
||||
scc_tree_dump_ctx_t *tree_dump, scc_ir_cprog_t *cprog,
|
||||
scc_ir_cprog_ctx_t *ir_ctx) {
|
||||
scc_tree_dump_ctx_t *tree_dump,
|
||||
scc_ir_cprog_t *cprog) {
|
||||
ctx->cprog = cprog;
|
||||
ctx->dump_ctx = tree_dump;
|
||||
ctx->ir_ctx = ir_ctx;
|
||||
}
|
||||
|
||||
void scc_ir_dump_node(scc_ir_dump_ctx_t *ctx, scc_ir_node_ref_t node_ref) {
|
||||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||||
scc_ir_node_t *node = scc_ir_module_get_node(GET_MODULE(ctx), node_ref);
|
||||
if (!node) {
|
||||
LOG_ERROR("Invalid node ref");
|
||||
return;
|
||||
@@ -283,7 +284,8 @@ void scc_ir_dump_node(scc_ir_dump_ctx_t *ctx, scc_ir_node_ref_t node_ref) {
|
||||
|
||||
if (node->type) {
|
||||
scc_tree_dump_printf(ctx->dump_ctx, " : ");
|
||||
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, node->type);
|
||||
scc_ir_type_t *type =
|
||||
scc_ir_module_get_type(GET_MODULE(ctx), node->type);
|
||||
if (type) {
|
||||
PRINT_VALUE(ctx->dump_ctx, "%s", get_type_tag_str(type->tag));
|
||||
}
|
||||
@@ -338,7 +340,7 @@ void scc_ir_dump_type(scc_ir_dump_ctx_t *ctx, scc_ir_type_ref_t type_ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, type_ref);
|
||||
scc_ir_type_t *type = scc_ir_module_get_type(GET_MODULE(ctx), type_ref);
|
||||
if (!type) {
|
||||
LOG_ERROR("invalid type ref");
|
||||
return;
|
||||
@@ -409,7 +411,8 @@ void scc_ir_dump_bblock(scc_ir_dump_ctx_t *ctx,
|
||||
return;
|
||||
}
|
||||
|
||||
scc_ir_bblock_t *bblock = scc_ir_ctx_get_bblock(ctx->ir_ctx, bblock_ref);
|
||||
scc_ir_bblock_t *bblock =
|
||||
scc_ir_module_get_bblock(GET_MODULE(ctx), bblock_ref);
|
||||
if (!bblock) {
|
||||
LOG_ERROR("invalid bblock ref");
|
||||
return;
|
||||
@@ -434,7 +437,7 @@ void scc_ir_dump_bblock(scc_ir_dump_ctx_t *ctx,
|
||||
|
||||
// 转储函数
|
||||
void scc_ir_dump_func(scc_ir_dump_ctx_t *ctx, scc_ir_func_ref_t func_ref) {
|
||||
scc_ir_func_t *func = scc_ir_ctx_get_func(ctx->ir_ctx, func_ref);
|
||||
scc_ir_func_t *func = scc_ir_module_get_func(GET_MODULE(ctx), func_ref);
|
||||
if (!ctx || !func) {
|
||||
LOG_ERROR("invalid parameter");
|
||||
return;
|
||||
@@ -489,7 +492,7 @@ void scc_ir_dump_cprog(scc_ir_dump_ctx_t *ctx) {
|
||||
// scc_ir_node_ref_t global_ref =
|
||||
// scc_vec_at(program->global_vals, i); scc_ir_node_t
|
||||
// *global_node =
|
||||
// scc_ir_ctx_get_node(ir_ctx, global_ref);
|
||||
// scc_ir_module_get_node(ir_ctx, global_ref);
|
||||
// if (global_node) {
|
||||
// scc_ir_dump_node(ctx, ir_ctx, global_node);
|
||||
// }
|
||||
@@ -526,17 +529,17 @@ void scc_ir_dump_cprog(scc_ir_dump_ctx_t *ctx) {
|
||||
|
||||
void scc_ir_dump_type_linear(scc_ir_dump_ctx_t *ctx,
|
||||
scc_ir_type_ref_t type_ref) {
|
||||
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, type_ref);
|
||||
scc_ir_type_t *type = scc_ir_module_get_type(GET_MODULE(ctx), type_ref);
|
||||
if (!ctx || !type) {
|
||||
LOG_ERROR("invalid parameter");
|
||||
return;
|
||||
}
|
||||
#define PRINT_TYPE(ctx, name) PRINT_VALUE(ctx, "%s", name)
|
||||
switch (type->tag) {
|
||||
case SCC_IR_TYPE_I32:
|
||||
case SCC_IR_TYPE_i32:
|
||||
PRINT_TYPE(ctx->dump_ctx, "i32");
|
||||
break;
|
||||
case SCC_IR_TYPE_VOID:
|
||||
case SCC_IR_TYPE_void:
|
||||
PRINT_TYPE(ctx->dump_ctx, "void");
|
||||
break;
|
||||
case SCC_IR_TYPE_ARRAY:
|
||||
@@ -577,7 +580,7 @@ void scc_ir_dump_type_linear(scc_ir_dump_ctx_t *ctx,
|
||||
// 辅助函数:输出节点引用或值到缓冲区
|
||||
static usize format_node_ref_or_value(scc_ir_dump_ctx_t *ctx, char *buf,
|
||||
usize size, scc_ir_node_ref_t node_ref) {
|
||||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||||
scc_ir_node_t *node = scc_ir_module_get_node(GET_MODULE(ctx), node_ref);
|
||||
if (!node) {
|
||||
return scc_snprintf(buf, size, "%%%u", node_ref);
|
||||
}
|
||||
@@ -598,7 +601,7 @@ static usize format_node_ref_or_value(scc_ir_dump_ctx_t *ctx, char *buf,
|
||||
// 线性输出节点信息(SSA IR风格)
|
||||
void scc_ir_dump_node_linear(scc_ir_dump_ctx_t *ctx,
|
||||
scc_ir_node_ref_t node_ref) {
|
||||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||||
scc_ir_node_t *node = scc_ir_module_get_node(GET_MODULE(ctx), node_ref);
|
||||
if (node == null) {
|
||||
LOG_ERROR("invalid node ref");
|
||||
return;
|
||||
@@ -707,8 +710,8 @@ void scc_ir_dump_node_linear(scc_ir_dump_ctx_t *ctx,
|
||||
break;
|
||||
|
||||
case SCC_IR_NODE_CALL: {
|
||||
char node_name[256] = "";
|
||||
char args_buf[256] = "";
|
||||
char node_name[256] = {0};
|
||||
char args_buf[256] = {0};
|
||||
char *args_p = args_buf;
|
||||
usize args_remaining = sizeof(args_buf);
|
||||
|
||||
@@ -727,7 +730,7 @@ void scc_ir_dump_node_linear(scc_ir_dump_ctx_t *ctx,
|
||||
}
|
||||
|
||||
scc_ir_func_t *func =
|
||||
scc_ir_ctx_get_func(ctx->ir_ctx, node->data.call.callee);
|
||||
scc_ir_module_get_func(GET_MODULE(ctx), node->data.call.callee);
|
||||
p += scc_snprintf(p, remaining, "call @%s(%s)",
|
||||
func ? func->name : null, args_buf);
|
||||
break;
|
||||
@@ -762,7 +765,8 @@ void scc_ir_dump_node_linear(scc_ir_dump_ctx_t *ctx,
|
||||
// 线性输出基本块信息
|
||||
void scc_ir_dump_bblock_linear(scc_ir_dump_ctx_t *ctx,
|
||||
scc_ir_bblock_ref_t bblock_ref) {
|
||||
scc_ir_bblock_t *bblock = scc_ir_ctx_get_bblock(ctx->ir_ctx, bblock_ref);
|
||||
scc_ir_bblock_t *bblock =
|
||||
scc_ir_module_get_bblock(GET_MODULE(ctx), bblock_ref);
|
||||
|
||||
if (bblock == null) {
|
||||
PRINT_NODE(ctx->dump_ctx, "<invalid block>\n");
|
||||
@@ -791,7 +795,7 @@ void scc_ir_dump_bblock_linear(scc_ir_dump_ctx_t *ctx,
|
||||
// 线性输出函数信息
|
||||
void scc_ir_dump_func_linear(scc_ir_dump_ctx_t *ctx,
|
||||
scc_ir_func_ref_t func_ref) {
|
||||
scc_ir_func_t *func = scc_ir_ctx_get_func(ctx->ir_ctx, func_ref);
|
||||
scc_ir_func_t *func = scc_ir_module_get_func(GET_MODULE(ctx), func_ref);
|
||||
if (!func) {
|
||||
LOG_ERROR("invalid function reference");
|
||||
return;
|
||||
@@ -816,7 +820,7 @@ void scc_ir_dump_func_linear(scc_ir_dump_ctx_t *ctx,
|
||||
scc_ir_node_ref_t param_ref = scc_vec_at(func->params, i);
|
||||
PRINT_NODE(ctx->dump_ctx, "%");
|
||||
scc_ir_node_t *param_node =
|
||||
scc_ir_ctx_get_node(ctx->ir_ctx, param_ref);
|
||||
scc_ir_module_get_node(GET_MODULE(ctx), param_ref);
|
||||
if (param_node && param_node->name && param_node->name[0] != '\0') {
|
||||
scc_snprintf(buff, sizeof(buff), "%u[%s]", param_ref,
|
||||
param_node->name);
|
||||
@@ -850,7 +854,8 @@ void scc_ir_dump_func_linear(scc_ir_dump_ctx_t *ctx,
|
||||
void scc_ir_dump_cprog_linear(scc_ir_dump_ctx_t *ctx) {
|
||||
scc_vec_foreach(ctx->cprog->func_decls, i) {
|
||||
scc_ir_func_ref_t func_decl = scc_vec_at(ctx->cprog->func_decls, i);
|
||||
scc_ir_func_t *func = scc_ir_ctx_get_func(ctx->ir_ctx, func_decl);
|
||||
scc_ir_func_t *func =
|
||||
scc_ir_module_get_func(GET_MODULE(ctx), func_decl);
|
||||
Assert(func != null);
|
||||
if (scc_vec_size(func->bblocks) == 0)
|
||||
scc_ir_dump_func_linear(ctx, func_decl);
|
||||
|
||||
151
libs/ir/src/ir_prog.c
Normal file
151
libs/ir/src/ir_prog.c
Normal file
@@ -0,0 +1,151 @@
|
||||
#include <ir_prog.h>
|
||||
|
||||
void scc_ir_cprog_init(scc_ir_cprog_t *in) {
|
||||
scc_vec_init(in->func_decls);
|
||||
scc_vec_init(in->func_defs);
|
||||
scc_vec_init(in->global_vals);
|
||||
scc_ir_module_init(&in->module);
|
||||
}
|
||||
|
||||
void scc_ir_cprog_drop(scc_ir_cprog_t *in) {
|
||||
scc_vec_free(in->func_decls);
|
||||
scc_vec_free(in->func_defs);
|
||||
scc_vec_free(in->global_vals);
|
||||
scc_ir_module_drop(&in->module);
|
||||
}
|
||||
|
||||
static u32 hash_key(const void *key) { return (u32)(usize)key; }
|
||||
static int cmp_key(const void *key1, const void *key2) {
|
||||
return (u32)(usize)key1 != (u32)(usize)key2;
|
||||
}
|
||||
|
||||
void scc_ir_module_init(scc_ir_module_t *ctx) {
|
||||
scc_vec_init(ctx->nodes);
|
||||
scc_vec_init(ctx->types);
|
||||
scc_vec_init(ctx->bblocks);
|
||||
scc_vec_init(ctx->funcs);
|
||||
scc_hashtable_init(&ctx->uid2nodes, hash_key, cmp_key);
|
||||
scc_hashtable_init(&ctx->uid2types, hash_key, cmp_key);
|
||||
scc_hashtable_init(&ctx->uid2bblocks, hash_key, cmp_key);
|
||||
scc_hashtable_init(&ctx->uid2funcs, hash_key, cmp_key);
|
||||
// 预留UID 0 作为无效引用
|
||||
ctx->node_uid = 1;
|
||||
ctx->type_uid = 1;
|
||||
ctx->bblock_uid = 1;
|
||||
ctx->func_uid = 1;
|
||||
}
|
||||
|
||||
void scc_ir_module_drop(scc_ir_module_t *ctx) {
|
||||
// 释放所有实体的内部内存
|
||||
for (usize i = 0; i < ctx->nodes.size; i++) {
|
||||
scc_ir_node_t *node = &ctx->nodes.data[i];
|
||||
scc_vec_free(node->used_by);
|
||||
if (node->tag == SCC_IR_NODE_CALL) {
|
||||
scc_vec_free(node->data.call.args);
|
||||
}
|
||||
}
|
||||
|
||||
for (usize i = 0; i < ctx->types.size; i++) {
|
||||
scc_ir_type_t *type = &ctx->types.data[i];
|
||||
if (type->tag == SCC_IR_TYPE_FUNC) {
|
||||
scc_vec_free(type->data.function.params);
|
||||
}
|
||||
}
|
||||
|
||||
for (usize i = 0; i < ctx->bblocks.size; i++) {
|
||||
scc_ir_bblock_t *bblock = &ctx->bblocks.data[i];
|
||||
scc_vec_free(bblock->instrs);
|
||||
}
|
||||
|
||||
for (usize i = 0; i < ctx->funcs.size; i++) {
|
||||
scc_ir_func_t *func = &ctx->funcs.data[i];
|
||||
scc_vec_free(func->params);
|
||||
scc_vec_free(func->bblocks);
|
||||
}
|
||||
|
||||
scc_vec_free(ctx->nodes);
|
||||
scc_vec_free(ctx->types);
|
||||
scc_vec_free(ctx->bblocks);
|
||||
scc_vec_free(ctx->funcs);
|
||||
scc_hashtable_drop(&ctx->uid2nodes);
|
||||
scc_hashtable_drop(&ctx->uid2types);
|
||||
scc_hashtable_drop(&ctx->uid2bblocks);
|
||||
scc_hashtable_drop(&ctx->uid2funcs);
|
||||
}
|
||||
|
||||
// 辅助宏:创建实体并添加到哈希表
|
||||
#define CREATE_ENTITY(ctx, vec, uid, data, hashtable) \
|
||||
do { \
|
||||
/* 分配新UID */ \
|
||||
unsigned new_uid = (ctx)->uid++; \
|
||||
/* 添加到向量 */ \
|
||||
scc_vec_push((vec), *(data)); \
|
||||
/* 添加到哈希表 */ \
|
||||
scc_hashtable_set(&(ctx)->hashtable, (const void *)(usize)new_uid, \
|
||||
(void *)(usize)(scc_vec_size(vec) - 1)); \
|
||||
return new_uid; \
|
||||
} while (0)
|
||||
|
||||
scc_ir_type_ref_t scc_ir_module_add_type(scc_ir_module_t *ctx,
|
||||
const scc_ir_type_t *type) {
|
||||
CREATE_ENTITY(ctx, ctx->types, type_uid, type, uid2types);
|
||||
}
|
||||
|
||||
scc_ir_node_ref_t scc_ir_module_add_node(scc_ir_module_t *ctx,
|
||||
const scc_ir_node_t *node) {
|
||||
CREATE_ENTITY(ctx, ctx->nodes, node_uid, node, uid2nodes);
|
||||
}
|
||||
|
||||
scc_ir_bblock_ref_t scc_ir_module_add_bblock(scc_ir_module_t *ctx,
|
||||
const scc_ir_bblock_t *bblock) {
|
||||
CREATE_ENTITY(ctx, ctx->bblocks, bblock_uid, bblock, uid2bblocks);
|
||||
}
|
||||
|
||||
scc_ir_func_ref_t scc_ir_module_add_func(scc_ir_module_t *ctx,
|
||||
const scc_ir_func_t *func) {
|
||||
CREATE_ENTITY(ctx, ctx->funcs, func_uid, func, uid2funcs);
|
||||
}
|
||||
|
||||
// 辅助宏:从哈希表获取索引
|
||||
#define GET_ENTITY_INDEX(ctx, ref, hashtable) \
|
||||
((usize)scc_hashtable_get(&(ctx)->hashtable, (void *)(usize)ref))
|
||||
|
||||
scc_ir_type_t *scc_ir_module_get_type(scc_ir_module_t *ctx,
|
||||
scc_ir_type_ref_t ref) {
|
||||
if (ref == 0)
|
||||
return null;
|
||||
usize idx = GET_ENTITY_INDEX(ctx, ref, uid2types);
|
||||
if (idx >= ctx->types.size)
|
||||
return null;
|
||||
return &ctx->types.data[idx];
|
||||
}
|
||||
|
||||
scc_ir_node_t *scc_ir_module_get_node(scc_ir_module_t *ctx,
|
||||
scc_ir_node_ref_t ref) {
|
||||
if (ref == 0)
|
||||
return null;
|
||||
usize idx = GET_ENTITY_INDEX(ctx, ref, uid2nodes);
|
||||
if (idx >= ctx->nodes.size)
|
||||
return null;
|
||||
return &ctx->nodes.data[idx];
|
||||
}
|
||||
|
||||
scc_ir_bblock_t *scc_ir_module_get_bblock(scc_ir_module_t *ctx,
|
||||
scc_ir_bblock_ref_t ref) {
|
||||
if (ref == 0)
|
||||
return null;
|
||||
usize idx = GET_ENTITY_INDEX(ctx, ref, uid2bblocks);
|
||||
if (idx >= ctx->bblocks.size)
|
||||
return null;
|
||||
return &ctx->bblocks.data[idx];
|
||||
}
|
||||
|
||||
scc_ir_func_t *scc_ir_module_get_func(scc_ir_module_t *ctx,
|
||||
scc_ir_func_ref_t ref) {
|
||||
if (ref == 0)
|
||||
return null;
|
||||
usize idx = GET_ENTITY_INDEX(ctx, ref, uid2funcs);
|
||||
if (idx >= ctx->funcs.size)
|
||||
return null;
|
||||
return &ctx->funcs.data[idx];
|
||||
}
|
||||
@@ -1,9 +1,27 @@
|
||||
#include <ir_base.h>
|
||||
#include <scc_ir.h>
|
||||
|
||||
void scc_ir_type_init(scc_ir_type_t *in, scc_ir_type_tag_t tag) {
|
||||
Assert(in != null);
|
||||
in->tag = tag;
|
||||
in->name = null;
|
||||
switch (tag) {
|
||||
case SCC_IR_TYPE_unknown:
|
||||
case SCC_IR_TYPE_void:
|
||||
case SCC_IR_TYPE_i8:
|
||||
case SCC_IR_TYPE_i16:
|
||||
case SCC_IR_TYPE_i32:
|
||||
case SCC_IR_TYPE_i64:
|
||||
case SCC_IR_TYPE_i128:
|
||||
case SCC_IR_TYPE_u8:
|
||||
case SCC_IR_TYPE_u16:
|
||||
case SCC_IR_TYPE_u32:
|
||||
case SCC_IR_TYPE_u64:
|
||||
case SCC_IR_TYPE_u128:
|
||||
case SCC_IR_TYPE_f16:
|
||||
case SCC_IR_TYPE_f32:
|
||||
case SCC_IR_TYPE_f64:
|
||||
case SCC_IR_TYPE_f128:
|
||||
break;
|
||||
case SCC_IR_TYPE_ARRAY:
|
||||
in->data.array.base = 0;
|
||||
in->data.array.len = 0;
|
||||
@@ -15,9 +33,6 @@ void scc_ir_type_init(scc_ir_type_t *in, scc_ir_type_tag_t tag) {
|
||||
scc_vec_init(in->data.function.params);
|
||||
in->data.function.ret_type = 0;
|
||||
break;
|
||||
case SCC_IR_TYPE_VOID:
|
||||
case SCC_IR_TYPE_I32:
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
@@ -53,7 +68,7 @@ void scc_ir_node_init(scc_ir_node_t *in, const char *name,
|
||||
break;
|
||||
case SCC_IR_NODE_CONST_INT:
|
||||
// TODO
|
||||
in->data.const_int.int32 = 0;
|
||||
in->data.const_int.int64 = 0;
|
||||
break;
|
||||
case SCC_IR_NODE_ALLOC:
|
||||
// TODO();
|
||||
@@ -94,15 +109,3 @@ void scc_ir_node_init(scc_ir_node_t *in, const char *name,
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void scc_ir_cprog_init(scc_ir_cprog_t *in) {
|
||||
scc_vec_init(in->func_decls);
|
||||
scc_vec_init(in->func_defs);
|
||||
scc_vec_init(in->global_vals);
|
||||
}
|
||||
|
||||
void scc_ir_cprog_drop(scc_ir_cprog_t *in) {
|
||||
scc_vec_free(in->func_decls);
|
||||
scc_vec_free(in->func_defs);
|
||||
scc_vec_free(in->global_vals);
|
||||
}
|
||||
@@ -29,7 +29,7 @@ typedef scc_hashtable_t *(*scc_reg_alloc_func_t)(
|
||||
);
|
||||
|
||||
typedef struct scc_reg_alloc {
|
||||
scc_ir_cprog_ctx_t *ir_ctx; ///< IR上下文
|
||||
scc_ir_module_t *ir_module; ///< IR存储节点
|
||||
scc_hashtable_t node_ref2reg_loc; ///< 输出结果哈希表
|
||||
scc_reg_loc_vec_t reg_loc_vec;
|
||||
int gpr_caller_saved; ///< 函数可以随意修改,调用者如果在意需自行保护.
|
||||
@@ -41,7 +41,7 @@ typedef struct scc_reg_alloc {
|
||||
#define scc_reg_alloc(ctx, func) ((ctx)->reg_alloc_func(ctx, func))
|
||||
|
||||
void scc_reg_alloc_init(scc_reg_alloc_t *ctx, scc_reg_alloc_func_t func,
|
||||
scc_ir_cprog_ctx_t *ir_ctx);
|
||||
scc_ir_module_t *ir_module);
|
||||
scc_hashtable_t *scc_reg_alloc_with_stack(scc_reg_alloc_t *ctx,
|
||||
scc_ir_func_t *func);
|
||||
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
#include <scc_ir.h>
|
||||
#include <scc_mcode.h>
|
||||
#include <sccf_builder.h>
|
||||
|
||||
typedef struct {
|
||||
scc_ir_cprog_t *cprog;
|
||||
scc_ir_cprog_ctx_t *ir_ctx;
|
||||
scc_mcode_t mcode;
|
||||
sccf_builder_t builder;
|
||||
sccf_builder_t *builder;
|
||||
scc_mcode_t sect_mcode;
|
||||
sccf_sect_data_t sect_data;
|
||||
|
||||
// FIXME
|
||||
usize stack_size;
|
||||
@@ -21,7 +22,9 @@ typedef struct {
|
||||
// amd64
|
||||
|
||||
void scc_ir2mcode_init(scc_ir2mcode_ctx_t *ctx, scc_ir_cprog_t *cprog,
|
||||
scc_ir_cprog_ctx_t *ir_ctx, scc_mcode_arch_t arch);
|
||||
sccf_builder_t *builder, scc_mcode_arch_t arch);
|
||||
void scc_ir2mcode_drop(scc_ir2mcode_ctx_t *ctx);
|
||||
|
||||
void scc_ir2mcode(scc_ir2mcode_ctx_t *ctx);
|
||||
|
||||
#endif /* __SCC_IR2MCODE_H__ */
|
||||
|
||||
@@ -3,10 +3,12 @@
|
||||
#include <reg_alloc.h>
|
||||
#include <scc_ir2mcode.h>
|
||||
|
||||
#define GET_MODULE(ctx) (&(ctx->cprog->module))
|
||||
|
||||
static void parse_location(scc_ir2mcode_ctx_t *ctx, scc_reg_loc_t *loc,
|
||||
scc_ir_node_ref_t node_ref) {
|
||||
Assert(ctx != null && loc != null);
|
||||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||||
scc_ir_node_t *node = scc_ir_module_get_node(GET_MODULE(ctx), node_ref);
|
||||
if (node == null) {
|
||||
LOG_FATAL("invalid node ref");
|
||||
UNREACHABLE();
|
||||
@@ -15,9 +17,10 @@ static void parse_location(scc_ir2mcode_ctx_t *ctx, scc_reg_loc_t *loc,
|
||||
usize idx = 0;
|
||||
switch (node->tag) {
|
||||
case SCC_IR_NODE_CONST_INT:
|
||||
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, node->type);
|
||||
scc_ir_type_t *type =
|
||||
scc_ir_module_get_type(GET_MODULE(ctx), node->type);
|
||||
Assert(type != 0);
|
||||
Assert(type->tag == SCC_IR_TYPE_U32 || type->tag == SCC_IR_TYPE_I32);
|
||||
Assert(type->tag == SCC_IR_TYPE_u32 || type->tag == SCC_IR_TYPE_i32);
|
||||
*loc = (scc_reg_loc_t){
|
||||
.kind = SCC_REG_KIND_IMM,
|
||||
.idx = (usize)node->data.const_int.int32,
|
||||
@@ -28,7 +31,8 @@ static void parse_location(scc_ir2mcode_ctx_t *ctx, scc_reg_loc_t *loc,
|
||||
TODO();
|
||||
break;
|
||||
case SCC_IR_NODE_FUNC_ARG_REF: {
|
||||
scc_ir_type_t *type = scc_ir_ctx_get_type(ctx->ir_ctx, node->type);
|
||||
scc_ir_type_t *type =
|
||||
scc_ir_module_get_type(GET_MODULE(ctx), node->type);
|
||||
Assert(type != 0);
|
||||
scc_reg_loc_t arg_loc;
|
||||
// arg_loc.kind = SCC_REG_KIND_FUNC_ARG;
|
||||
@@ -101,7 +105,7 @@ typedef SCC_VEC(patch_t) patch_vec_t;
|
||||
|
||||
static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
patch_vec_t *patches) {
|
||||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||||
scc_ir_node_t *node = scc_ir_module_get_node(GET_MODULE(ctx), node_ref);
|
||||
if (node == null) {
|
||||
LOG_ERROR("invalid node ref");
|
||||
return;
|
||||
@@ -126,8 +130,8 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
scc_reg_loc_t to;
|
||||
parse_location(ctx, &from, node->data.load.target);
|
||||
parse_location(ctx, &to, node_ref);
|
||||
load_value_to_reg(&ctx->mcode, &from, SCC_AMD64_RAX);
|
||||
store_value_from_reg(&ctx->mcode, &to, SCC_AMD64_RAX);
|
||||
load_value_to_reg(&ctx->sect_mcode, &from, SCC_AMD64_RAX);
|
||||
store_value_from_reg(&ctx->sect_mcode, &to, SCC_AMD64_RAX);
|
||||
break;
|
||||
}
|
||||
case SCC_IR_NODE_STORE: ///< 存储数据
|
||||
@@ -136,8 +140,8 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
scc_reg_loc_t to;
|
||||
parse_location(ctx, &from, node->data.store.value);
|
||||
parse_location(ctx, &to, node->data.store.target);
|
||||
load_value_to_reg(&ctx->mcode, &from, SCC_AMD64_RAX);
|
||||
store_value_from_reg(&ctx->mcode, &to, SCC_AMD64_RAX);
|
||||
load_value_to_reg(&ctx->sect_mcode, &from, SCC_AMD64_RAX);
|
||||
store_value_from_reg(&ctx->sect_mcode, &to, SCC_AMD64_RAX);
|
||||
break;
|
||||
}
|
||||
case SCC_IR_NODE_GET_PTR: ///< 获取指针
|
||||
@@ -153,20 +157,20 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
parse_location(ctx, &loc_res, node_ref);
|
||||
|
||||
// 将左操作数加载到 RAX(临时结果寄存器)
|
||||
load_value_to_reg(&ctx->mcode, &loc_lhs, SCC_AMD64_RAX);
|
||||
load_value_to_reg(&ctx->sect_mcode, &loc_lhs, SCC_AMD64_RAX);
|
||||
// 将右操作数加载到 RCX
|
||||
load_value_to_reg(&ctx->mcode, &loc_rhs, SCC_AMD64_RCX);
|
||||
load_value_to_reg(&ctx->sect_mcode, &loc_rhs, SCC_AMD64_RCX);
|
||||
switch (node->data.op.op) {
|
||||
case SCC_IR_OP_ADD:
|
||||
scc_mcode_amd64_add_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_add_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
break;
|
||||
case SCC_IR_OP_SUB:
|
||||
scc_mcode_amd64_sub_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_sub_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
break;
|
||||
case SCC_IR_OP_MUL:
|
||||
scc_mcode_amd64_mul_r64(&ctx->mcode, SCC_AMD64_RCX);
|
||||
scc_mcode_amd64_mul_r64(&ctx->sect_mcode, SCC_AMD64_RCX);
|
||||
break;
|
||||
// [SCC_IR_OP_EMPTY] = "empty", [SCC_IR_OP_NEQ] = "!=",
|
||||
// [SCC_IR_OP_EQ] = "==", [SCC_IR_OP_GT] = ">",
|
||||
@@ -179,51 +183,51 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
// [SCC_IR_OP_SHL] = "<<", [SCC_IR_OP_SHR] = ">>",
|
||||
// [SCC_IR_OP_SAR] = ">>a", // Arithmetic shift right
|
||||
case SCC_IR_OP_NEQ:
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
scc_mcode_amd64_setcc_r8(&ctx->mcode, SCC_AMD64_COND_NE,
|
||||
scc_mcode_amd64_setcc_r8(&ctx->sect_mcode, SCC_AMD64_COND_NE,
|
||||
SCC_AMD64_RAX);
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RAX);
|
||||
break;
|
||||
case SCC_IR_OP_EQ:
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
scc_mcode_amd64_setcc_r8(&ctx->mcode, SCC_AMD64_COND_E,
|
||||
scc_mcode_amd64_setcc_r8(&ctx->sect_mcode, SCC_AMD64_COND_E,
|
||||
SCC_AMD64_RAX);
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RAX);
|
||||
break;
|
||||
case SCC_IR_OP_GT:
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
scc_mcode_amd64_setcc_r8(&ctx->mcode, SCC_AMD64_COND_G,
|
||||
scc_mcode_amd64_setcc_r8(&ctx->sect_mcode, SCC_AMD64_COND_G,
|
||||
SCC_AMD64_RAX);
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RAX);
|
||||
break;
|
||||
case SCC_IR_OP_LT:
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
scc_mcode_amd64_setcc_r8(&ctx->mcode, SCC_AMD64_COND_L,
|
||||
scc_mcode_amd64_setcc_r8(&ctx->sect_mcode, SCC_AMD64_COND_L,
|
||||
SCC_AMD64_RAX);
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RAX);
|
||||
break;
|
||||
case SCC_IR_OP_GE:
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
scc_mcode_amd64_setcc_r8(&ctx->mcode, SCC_AMD64_COND_GE,
|
||||
scc_mcode_amd64_setcc_r8(&ctx->sect_mcode, SCC_AMD64_COND_GE,
|
||||
SCC_AMD64_RAX);
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RAX);
|
||||
break;
|
||||
case SCC_IR_OP_LE:
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_cmp_r64_r64(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RCX);
|
||||
scc_mcode_amd64_setcc_r8(&ctx->mcode, SCC_AMD64_COND_LE,
|
||||
scc_mcode_amd64_setcc_r8(&ctx->sect_mcode, SCC_AMD64_COND_LE,
|
||||
SCC_AMD64_RAX);
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->mcode, SCC_AMD64_RAX,
|
||||
scc_mcode_amd64_movzx_r64_r8(&ctx->sect_mcode, SCC_AMD64_RAX,
|
||||
SCC_AMD64_RAX);
|
||||
break;
|
||||
default:
|
||||
@@ -231,7 +235,7 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
break;
|
||||
}
|
||||
// 将 RAX 中的结果存储到 res 位置
|
||||
store_value_from_reg(&ctx->mcode, &loc_res, SCC_AMD64_RAX);
|
||||
store_value_from_reg(&ctx->sect_mcode, &loc_res, SCC_AMD64_RAX);
|
||||
break;
|
||||
}
|
||||
///< 有条件分支
|
||||
@@ -239,16 +243,16 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
scc_reg_loc_t loc;
|
||||
parse_location(ctx, &loc, node->data.branch.cond);
|
||||
// (void)loc;
|
||||
load_value_to_reg(&ctx->mcode, &loc, SCC_AMD64_RAX);
|
||||
scc_mcode_amd64_cmp_r64_imm32(&ctx->mcode, SCC_AMD64_RAX, 0);
|
||||
load_value_to_reg(&ctx->sect_mcode, &loc, SCC_AMD64_RAX);
|
||||
scc_mcode_amd64_cmp_r64_imm32(&ctx->sect_mcode, SCC_AMD64_RAX, 0);
|
||||
|
||||
scc_mcode_amd64_jcc_rel32(&ctx->mcode, SCC_AMD64_COND_NE, 0);
|
||||
patch_t patch_true = {.pos = scc_vec_size(ctx->mcode.mcode),
|
||||
scc_mcode_amd64_jcc_rel32(&ctx->sect_mcode, SCC_AMD64_COND_NE, 0);
|
||||
patch_t patch_true = {.pos = scc_vec_size(ctx->sect_mcode.mcode),
|
||||
.target_bb_ref =
|
||||
(usize)node->data.branch.true_bblock};
|
||||
scc_vec_push(*patches, patch_true);
|
||||
scc_mcode_amd64_jmp_rel32(&ctx->mcode, 0);
|
||||
patch_t patch_false = {.pos = scc_vec_size(ctx->mcode.mcode),
|
||||
scc_mcode_amd64_jmp_rel32(&ctx->sect_mcode, 0);
|
||||
patch_t patch_false = {.pos = scc_vec_size(ctx->sect_mcode.mcode),
|
||||
.target_bb_ref =
|
||||
(usize)node->data.branch.false_bblock};
|
||||
scc_vec_push(*patches, patch_false);
|
||||
@@ -256,8 +260,8 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
}
|
||||
///< 无条件跳转
|
||||
case SCC_IR_NODE_JUMP: {
|
||||
scc_mcode_amd64_jmp_rel32(&ctx->mcode, 0);
|
||||
usize pos = scc_vec_size(ctx->mcode.mcode);
|
||||
scc_mcode_amd64_jmp_rel32(&ctx->sect_mcode, 0);
|
||||
usize pos = scc_vec_size(ctx->sect_mcode.mcode);
|
||||
patch_t patch = {.pos = pos,
|
||||
.target_bb_ref = (usize)node->data.jump.target_bblock};
|
||||
scc_vec_push(*patches, patch);
|
||||
@@ -277,13 +281,13 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
scc_vec_foreach(node->data.call.args, i) {
|
||||
parse_location(ctx, &loc, scc_vec_at(node->data.call.args, i));
|
||||
if (i == 0) {
|
||||
load_value_to_reg(&ctx->mcode, &loc, SCC_AMD64_RCX);
|
||||
load_value_to_reg(&ctx->sect_mcode, &loc, SCC_AMD64_RCX);
|
||||
} else if (i == 1) {
|
||||
load_value_to_reg(&ctx->mcode, &loc, SCC_AMD64_RDX);
|
||||
load_value_to_reg(&ctx->sect_mcode, &loc, SCC_AMD64_RDX);
|
||||
} else if (i == 2) {
|
||||
load_value_to_reg(&ctx->mcode, &loc, SCC_AMD64_R8);
|
||||
load_value_to_reg(&ctx->sect_mcode, &loc, SCC_AMD64_R8);
|
||||
} else if (i == 3) {
|
||||
load_value_to_reg(&ctx->mcode, &loc, SCC_AMD64_R9);
|
||||
load_value_to_reg(&ctx->sect_mcode, &loc, SCC_AMD64_R9);
|
||||
} else {
|
||||
LOG_FATAL("not support more than 4 args");
|
||||
}
|
||||
@@ -291,32 +295,33 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
}
|
||||
|
||||
scc_ir_func_t *func =
|
||||
scc_ir_ctx_get_func(ctx->ir_ctx, node->data.call.callee);
|
||||
scc_ir_module_get_func(GET_MODULE(ctx), node->data.call.callee);
|
||||
if (!func) {
|
||||
LOG_ERROR("invalid function reference");
|
||||
return;
|
||||
}
|
||||
|
||||
scc_mcode_amd64_call_rel32(&ctx->mcode, 0);
|
||||
usize sym_idx = sccf_builder_get_symbol_idx(&ctx->builder, func->name);
|
||||
scc_mcode_amd64_call_rel32(&ctx->sect_mcode, 0);
|
||||
usize sym_idx = sccf_builder_get_symbol_idx(ctx->builder, func->name);
|
||||
Assert(sym_idx != 0);
|
||||
sccf_builder_add_reloc(&ctx->builder,
|
||||
(sccf_reloc_t){
|
||||
.reloc_type = SCCF_RELOC_TYPE_REL,
|
||||
.offset = scc_vec_size(ctx->mcode.mcode) - 4,
|
||||
.addend = 4,
|
||||
.sect_type = SCCF_SECT_CODE,
|
||||
.sym_idx = sym_idx,
|
||||
});
|
||||
sccf_builder_add_reloc(
|
||||
ctx->builder, (sccf_reloc_t){
|
||||
.reloc_type = SCCF_RELOC_TYPE_REL,
|
||||
.offset = scc_vec_size(ctx->sect_mcode.mcode) - 4,
|
||||
.addend = 4,
|
||||
.sect_type = SCCF_SECT_CODE,
|
||||
.sym_idx = sym_idx,
|
||||
});
|
||||
|
||||
// 处理返回值
|
||||
scc_ir_type_t *func_type = scc_ir_ctx_get_type(ctx->ir_ctx, func->type);
|
||||
scc_ir_type_t *func_type =
|
||||
scc_ir_module_get_type(GET_MODULE(ctx), func->type);
|
||||
Assert(func_type);
|
||||
scc_ir_type_t *ret_type =
|
||||
scc_ir_ctx_get_type(ctx->ir_ctx, func_type->data.function.ret_type);
|
||||
if (ret_type && ret_type->tag != SCC_IR_TYPE_VOID) {
|
||||
scc_ir_type_t *ret_type = scc_ir_module_get_type(
|
||||
GET_MODULE(ctx), func_type->data.function.ret_type);
|
||||
if (ret_type && ret_type->tag != SCC_IR_TYPE_void) {
|
||||
parse_location(ctx, &loc, node_ref);
|
||||
store_value_from_reg(&ctx->mcode, &loc, SCC_AMD64_RAX);
|
||||
store_value_from_reg(&ctx->sect_mcode, &loc, SCC_AMD64_RAX);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -325,11 +330,11 @@ static void parse_node(scc_ir2mcode_ctx_t *ctx, scc_ir_bblock_ref_t node_ref,
|
||||
if (node->data.ret.ret_val) {
|
||||
scc_reg_loc_t loc;
|
||||
parse_location(ctx, &loc, node->data.ret.ret_val);
|
||||
load_value_to_reg(&ctx->mcode, &loc, SCC_AMD64_RAX);
|
||||
load_value_to_reg(&ctx->sect_mcode, &loc, SCC_AMD64_RAX);
|
||||
}
|
||||
scc_mcode_amd64_add_rsp_imm32(&ctx->mcode, ctx->stack_size);
|
||||
scc_mcode_amd64_pop_r64(&ctx->mcode, SCC_AMD64_RBP);
|
||||
scc_mcode_amd64_ret(&ctx->mcode);
|
||||
scc_mcode_amd64_add_rsp_imm32(&ctx->sect_mcode, ctx->stack_size);
|
||||
scc_mcode_amd64_pop_r64(&ctx->sect_mcode, SCC_AMD64_RBP);
|
||||
scc_mcode_amd64_ret(&ctx->sect_mcode);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -374,24 +379,24 @@ static void parse_function(scc_ir2mcode_ctx_t *ctx, scc_ir_func_t *func) {
|
||||
patch_vec_t patches;
|
||||
scc_vec_init(patches);
|
||||
|
||||
scc_mcode_amd64_push_r64(&ctx->mcode, SCC_AMD64_RBP);
|
||||
scc_mcode_amd64_sub_rsp_imm32(&ctx->mcode, ctx->stack_size);
|
||||
scc_mcode_amd64_lea_r64_m64_disp32(&ctx->mcode, SCC_AMD64_RBP,
|
||||
scc_mcode_amd64_push_r64(&ctx->sect_mcode, SCC_AMD64_RBP);
|
||||
scc_mcode_amd64_sub_rsp_imm32(&ctx->sect_mcode, ctx->stack_size);
|
||||
scc_mcode_amd64_lea_r64_m64_disp32(&ctx->sect_mcode, SCC_AMD64_RBP,
|
||||
SCC_AMD64_RSP, ctx->stack_size);
|
||||
scc_reg_loc_t loc;
|
||||
scc_vec_foreach(func->params, i) {
|
||||
// scc_ir_node_t *param =
|
||||
// scc_ir_ctx_get_node(ctx->ir_ctx, );
|
||||
// scc_ir_module_get_node(GET_MODULE(ctx), );
|
||||
scc_ir_node_ref_t node_ref = scc_vec_at(func->params, i);
|
||||
parse_location(ctx, &loc, node_ref);
|
||||
if (i == 0) {
|
||||
store_value_from_reg(&ctx->mcode, &loc, SCC_AMD64_RCX);
|
||||
store_value_from_reg(&ctx->sect_mcode, &loc, SCC_AMD64_RCX);
|
||||
} else if (i == 1) {
|
||||
store_value_from_reg(&ctx->mcode, &loc, SCC_AMD64_RDX);
|
||||
store_value_from_reg(&ctx->sect_mcode, &loc, SCC_AMD64_RDX);
|
||||
} else if (i == 2) {
|
||||
store_value_from_reg(&ctx->mcode, &loc, SCC_AMD64_R8);
|
||||
store_value_from_reg(&ctx->sect_mcode, &loc, SCC_AMD64_R8);
|
||||
} else if (i == 3) {
|
||||
store_value_from_reg(&ctx->mcode, &loc, SCC_AMD64_R9);
|
||||
store_value_from_reg(&ctx->sect_mcode, &loc, SCC_AMD64_R9);
|
||||
} else {
|
||||
LOG_FATAL("not support more than 4 args");
|
||||
}
|
||||
@@ -401,19 +406,19 @@ static void parse_function(scc_ir2mcode_ctx_t *ctx, scc_ir_func_t *func) {
|
||||
for (usize i = 0; i < scc_vec_size(func->bblocks); i++) {
|
||||
scc_ir_bblock_ref_t bblock_ref = scc_vec_at(func->bblocks, i);
|
||||
scc_ir_bblock_t *bblock =
|
||||
scc_ir_ctx_get_bblock(ctx->ir_ctx, bblock_ref);
|
||||
scc_ir_module_get_bblock(GET_MODULE(ctx), bblock_ref);
|
||||
|
||||
if (bblock == null) {
|
||||
LOG_FATAL("<invalid block>\n");
|
||||
return;
|
||||
}
|
||||
|
||||
bblock_offsets[i] = scc_vec_size(ctx->mcode.mcode);
|
||||
bblock_offsets[i] = scc_vec_size(ctx->sect_mcode.mcode);
|
||||
parse_bblock(ctx, bblock, &patches);
|
||||
}
|
||||
|
||||
// 回填所有跳转偏移
|
||||
u8 *buf = scc_vec_unsafe_get_data(ctx->mcode.mcode);
|
||||
u8 *buf = scc_vec_unsafe_get_data(ctx->sect_mcode.mcode);
|
||||
scc_vec_foreach(patches, idx) {
|
||||
patch_t *p = &scc_vec_at(patches, idx);
|
||||
usize target_id =
|
||||
@@ -430,11 +435,12 @@ static void parse_function(scc_ir2mcode_ctx_t *ctx, scc_ir_func_t *func) {
|
||||
}
|
||||
|
||||
void scc_ir2amd64(scc_ir2mcode_ctx_t *ctx) {
|
||||
scc_reg_alloc_init(&ctx->reg_alloc, scc_reg_alloc_with_stack, ctx->ir_ctx);
|
||||
scc_reg_alloc_init(&ctx->reg_alloc, scc_reg_alloc_with_stack,
|
||||
GET_MODULE(ctx));
|
||||
|
||||
scc_vec_foreach(ctx->cprog->func_decls, i) {
|
||||
scc_ir_node_ref_t func_ref = scc_vec_at(ctx->cprog->func_decls, i);
|
||||
scc_ir_func_t *func = scc_ir_ctx_get_func(ctx->ir_ctx, func_ref);
|
||||
scc_ir_func_t *func = scc_ir_module_get_func(GET_MODULE(ctx), func_ref);
|
||||
if (!func) {
|
||||
LOG_ERROR("invalid function reference");
|
||||
return;
|
||||
@@ -460,40 +466,31 @@ void scc_ir2amd64(scc_ir2mcode_ctx_t *ctx) {
|
||||
.sccf_sym_vis = SCCF_SYM_VIS_DEFAULT,
|
||||
};
|
||||
}
|
||||
usize sym_idx =
|
||||
sccf_builder_add_symbol(&ctx->builder, func->name, &sym);
|
||||
usize sym_idx = sccf_builder_add_symbol(ctx->builder, func->name, &sym);
|
||||
Assert(sym_idx != 0);
|
||||
}
|
||||
|
||||
scc_vec_foreach(ctx->cprog->func_defs, i) {
|
||||
scc_ir_node_ref_t func_ref = scc_vec_at(ctx->cprog->func_defs, i);
|
||||
scc_ir_func_t *func = scc_ir_ctx_get_func(ctx->ir_ctx, func_ref);
|
||||
scc_ir_func_t *func = scc_ir_module_get_func(GET_MODULE(ctx), func_ref);
|
||||
if (!func) {
|
||||
LOG_ERROR("invalid function reference");
|
||||
return;
|
||||
}
|
||||
sccf_sym_t *sym =
|
||||
sccf_builder_get_symbol_unsafe(&ctx->builder, func->name);
|
||||
sccf_builder_get_symbol_unsafe(ctx->builder, func->name);
|
||||
Assert(sym != null);
|
||||
sym->sccf_sect_offset = scc_vec_size(ctx->mcode.mcode);
|
||||
sym->sccf_sect_offset = scc_vec_size(ctx->sect_mcode.mcode);
|
||||
parse_function(ctx, func);
|
||||
}
|
||||
sccf_sect_data_t text_section;
|
||||
scc_vec_unsafe_from_buffer(text_section,
|
||||
scc_vec_unsafe_get_data(ctx->mcode.mcode),
|
||||
scc_vec_size(ctx->mcode.mcode));
|
||||
sccf_builder_add_text_section(&ctx->builder, &text_section);
|
||||
sccf_sect_data_t data_section;
|
||||
scc_vec_init(data_section);
|
||||
sccf_builder_add_data_section(&ctx->builder, &data_section);
|
||||
|
||||
u8 *buf = scc_vec_unsafe_get_data(ctx->mcode.mcode);
|
||||
scc_vec_foreach(ctx->builder.relocs, i) {
|
||||
sccf_reloc_t *reloc = &scc_vec_at(ctx->builder.relocs, i);
|
||||
u8 *buf = scc_vec_unsafe_get_data(ctx->sect_mcode.mcode);
|
||||
scc_vec_foreach(ctx->builder->relocs, i) {
|
||||
sccf_reloc_t *reloc = &scc_vec_at(ctx->builder->relocs, i);
|
||||
if (reloc->sym_idx == 0) {
|
||||
Panic("relocate to an invalid symbol");
|
||||
}
|
||||
sccf_sym_t *sym = &scc_vec_at(ctx->builder.symtab, reloc->sym_idx);
|
||||
sccf_sym_t *sym = &scc_vec_at(ctx->builder->symtab, reloc->sym_idx);
|
||||
if (sym->sccf_sym_type != SCCF_SYM_TYPE_EXTERN) {
|
||||
Assert(reloc->reloc_type == SCCF_RELOC_TYPE_REL);
|
||||
|
||||
@@ -508,6 +505,15 @@ void scc_ir2amd64(scc_ir2mcode_ctx_t *ctx) {
|
||||
reloc->reloc_type = SCCF_RELOC_TYPE_EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
sccf_sect_data_t text_section;
|
||||
scc_vec_unsafe_from_buffer(text_section,
|
||||
scc_vec_unsafe_get_data(ctx->sect_mcode.mcode),
|
||||
scc_vec_size(ctx->sect_mcode.mcode));
|
||||
sccf_builder_add_text_section(ctx->builder, &text_section);
|
||||
sccf_sect_data_t data_section;
|
||||
scc_vec_init(data_section);
|
||||
sccf_builder_add_data_section(ctx->builder, &data_section);
|
||||
// FIXME
|
||||
ctx->builder.entry_symbol_name = "main";
|
||||
ctx->builder->entry_symbol_name = "main";
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ int equal_func(const void *key1, const void *key2) {
|
||||
}
|
||||
|
||||
void scc_reg_alloc_init(scc_reg_alloc_t *ctx, scc_reg_alloc_func_t func,
|
||||
scc_ir_cprog_ctx_t *ir_ctx) {
|
||||
scc_ir_module_t *ir_module) {
|
||||
ctx->gpr_caller_saved = 0;
|
||||
ctx->gpr_callee_saved = 0;
|
||||
ctx->ir_ctx = ir_ctx;
|
||||
ctx->ir_module = ir_module;
|
||||
ctx->reg_alloc_func = func;
|
||||
|
||||
ctx->alloc_stack_size = 0;
|
||||
@@ -37,16 +37,18 @@ scc_hashtable_t *scc_reg_alloc_with_stack(scc_reg_alloc_t *ctx,
|
||||
scc_vec_foreach(func->bblocks, i) {
|
||||
scc_ir_bblock_ref_t bblock_ref = scc_vec_at(func->bblocks, i);
|
||||
scc_ir_bblock_t *bblock =
|
||||
scc_ir_ctx_get_bblock(ctx->ir_ctx, bblock_ref);
|
||||
scc_ir_module_get_bblock(ctx->ir_module, bblock_ref);
|
||||
Assert(bblock != null);
|
||||
scc_vec_foreach(bblock->instrs, j) {
|
||||
scc_ir_node_ref_t node_ref = scc_vec_at(bblock->instrs, j);
|
||||
scc_ir_node_t *node = scc_ir_ctx_get_node(ctx->ir_ctx, node_ref);
|
||||
scc_ir_node_t *node =
|
||||
scc_ir_module_get_node(ctx->ir_module, node_ref);
|
||||
Assert(node != null);
|
||||
loc.kind = SCC_REG_KIND_UNDEF;
|
||||
switch (node->tag) {
|
||||
case SCC_IR_NODE_LOAD:
|
||||
case SCC_IR_NODE_OP:
|
||||
|
||||
case SCC_IR_NODE_ALLOC: {
|
||||
loc.kind = SCC_REG_KIND_STACK;
|
||||
loc.idx = ctx->alloc_stack_size;
|
||||
@@ -61,11 +63,11 @@ scc_hashtable_t *scc_reg_alloc_with_stack(scc_reg_alloc_t *ctx,
|
||||
case SCC_IR_NODE_CALL: {
|
||||
// 处理返回值
|
||||
scc_ir_type_t *func_type =
|
||||
scc_ir_ctx_get_type(ctx->ir_ctx, func->type);
|
||||
scc_ir_module_get_type(ctx->ir_module, func->type);
|
||||
Assert(func_type);
|
||||
scc_ir_type_t *ret_type = scc_ir_ctx_get_type(
|
||||
ctx->ir_ctx, func_type->data.function.ret_type);
|
||||
if (ret_type && ret_type->tag != SCC_IR_TYPE_VOID) {
|
||||
scc_ir_type_t *ret_type = scc_ir_module_get_type(
|
||||
ctx->ir_module, func_type->data.function.ret_type);
|
||||
if (ret_type && ret_type->tag != SCC_IR_TYPE_void) {
|
||||
loc.kind = SCC_REG_KIND_STACK;
|
||||
loc.idx = ctx->alloc_stack_size;
|
||||
ctx->alloc_stack_size += 8;
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#include <scc_ir2mcode.h>
|
||||
|
||||
void scc_ir2mcode_init(scc_ir2mcode_ctx_t *ctx, scc_ir_cprog_t *cprog,
|
||||
scc_ir_cprog_ctx_t *ir_ctx, scc_mcode_arch_t arch) {
|
||||
sccf_builder_t *builder, scc_mcode_arch_t arch) {
|
||||
ctx->cprog = cprog;
|
||||
ctx->ir_ctx = ir_ctx;
|
||||
scc_mcode_init(&ctx->mcode, arch);
|
||||
sccf_builder_init(&ctx->builder);
|
||||
ctx->builder = builder;
|
||||
scc_mcode_init(&ctx->sect_mcode, arch);
|
||||
scc_vec_init(ctx->sect_data);
|
||||
sccf_builder_init(ctx->builder);
|
||||
}
|
||||
|
||||
void scc_ir2mcode_drop(scc_ir2mcode_ctx_t *ctx) {}
|
||||
|
||||
void scc_ir2amd64(scc_ir2mcode_ctx_t *ctx);
|
||||
|
||||
void scc_ir2mcode(scc_ir2mcode_ctx_t *ctx) { scc_ir2amd64(ctx); }
|
||||
|
||||
@@ -31,15 +31,20 @@ void test_example(const char *input, cbool need_sema, const char *name) {
|
||||
|
||||
scc_ast2ir_ctx_t ast2ir_ctx;
|
||||
#include <abi/win_x64_type_abi.h>
|
||||
scc_ast2ir_ctx_init(&ast2ir_ctx, scc_win_x64_type_abi);
|
||||
scc_ir_cprog_t cprog;
|
||||
scc_ir_cprog_init(&cprog);
|
||||
scc_ast2ir_ctx_init(&ast2ir_ctx, scc_win_x64_type_abi, &cprog);
|
||||
scc_ast2ir_translation_unit(&ast2ir_ctx, tu);
|
||||
scc_ast2ir_ctx_drop(&ast2ir_ctx);
|
||||
|
||||
scc_ir2mcode_ctx_t mcode_ctx;
|
||||
scc_ir2mcode_init(&mcode_ctx, &ast2ir_ctx.builder.cprog,
|
||||
&ast2ir_ctx.builder.ctx, SCC_MCODE_ARCH_AMD64);
|
||||
scc_ir2mcode(&mcode_ctx);
|
||||
scc_ir2mcode_ctx_t ir2mcode_ctx;
|
||||
sccf_builder_t sccf_builder;
|
||||
scc_ir2mcode_init(&ir2mcode_ctx, &cprog, &sccf_builder,
|
||||
SCC_MCODE_ARCH_AMD64);
|
||||
scc_ir2mcode(&ir2mcode_ctx);
|
||||
scc_ir2mcode_drop(&ir2mcode_ctx);
|
||||
|
||||
const sccf_t *sccf = sccf_builder_to_sccf(&mcode_ctx.builder);
|
||||
const sccf_t *sccf = sccf_builder_to_sccf(&sccf_builder);
|
||||
scc_pe_builder_t pe_builder;
|
||||
sccf2pe(&pe_builder, sccf);
|
||||
|
||||
@@ -82,6 +87,24 @@ int main() {
|
||||
"int main(void) {\n"
|
||||
" return add(1, 2);\n"
|
||||
"}\n",
|
||||
true, "10_call.exe");
|
||||
true, "10_main.exe");
|
||||
test_example("int factorial(int);\n"
|
||||
"\n"
|
||||
"int main() {\n"
|
||||
" int num = 5;\n"
|
||||
" int result = factorial(num);\n"
|
||||
" // printf(\"%d\", result);\n"
|
||||
" return result;\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"int factorial(int num) {\n"
|
||||
" if (num == 0) {\n"
|
||||
" return 1;\n"
|
||||
" } else {\n"
|
||||
" return num * factorial(num - 1);\n"
|
||||
" }\n"
|
||||
"}\n",
|
||||
true, "11_recursion.exe");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
300
runtime/scc_core/include/scc_printf/README.md
Normal file
300
runtime/scc_core/include/scc_printf/README.md
Normal file
@@ -0,0 +1,300 @@
|
||||
# Standalone printf/sprintf formatted printing function library
|
||||
|
||||
[](https://github.com/eyalroz/printf/actions/workflows/build_and_test.yml)
|
||||
[](https://raw.githubusercontent.com/eyalroz/printf/master/LICENSE)
|
||||
[](http://github.com/eyalroz/printf/issues)
|
||||
<sup>Parent repository: </sup>[](http://github.com/mpaland/printf/issues)
|
||||
<sup>Package managers: </sup>[](https://github.com/cpp-pm/hunter/blob/master/examples/eyalroz_printf/CMakeLists.txt)
|
||||
<!-- Can't use Travis - they stopped offering free builds [](https://travis-ci.com/eyalroz/printf) -->
|
||||
<!-- No releases yet... [](https://github.com/mpaland/eyalroz/releases)-->
|
||||
|
||||
|
||||
| Table of contents |
|
||||
|:------------------|
|
||||
|<sub>[Thinking of forking this repository?](#thinking-of-forking-this-repository-read-this-first)<br>[Highlights, design goals and the mpaland->eyalroz fork](#highlights-design-goals-and-the-mpaland-eyalroz-fork)<br>[Using the `printf` library in your project](#using-the-printf-library-in-your-project)<br> - [CMake options and preprocessor definitions](#cmake-options-and-preprocessor-definitions)<br> - [Reducing compiled code size](#reducing-compiled-code-size)<br>[Library API](#library-api)<br> - [Implemented functions](#implemented-functions)<br> - [Supported Format Specifiers](#supported-format-specifiers)<br> - [Return Value](#return-value)<br>[Contributing](#contributing)<br>[License](#license) </sub>|
|
||||
|
||||
This is a small but **fully-loaded** implementation of C's formatted printing family of functions. It was originally designed by Marco Paland, with the primary use case being in embedded systems - where these functions are unavailable, or when one needs to avoid the memory footprint of linking against a full-fledged libc. The library can be made even smaller by partially excluding some of the supported format specifiers during compilation. The library stands alone, with **No external dependencies**.
|
||||
|
||||
It is a fork of the original [mpaland/printf](https://github.com/mpaland/printf) repository by [Marco Paland](https://github.com/mpaland), with multiple bug fixes and a few more features.
|
||||
|
||||
## Thinking of forking this repository? Read this first!
|
||||
|
||||
If you've decided you want to work on your own version of this repository - please don't just fork it!
|
||||
|
||||
* If you just want a stable codebase - use one of the [versioned releases](https://github.com/eyalroz/printf/releases).
|
||||
* If you want to contribute by adding a feature or supporting a new platform - see [contributing](#contributing) below.
|
||||
* If you want to make customizations/changes which are only relevant for your own project - please **rename** your fork (e.g. `myproj-printf` or `printf-for-mypurpose`).
|
||||
|
||||
Why? Because we already have a mess of 381 forks (!) as of January 2023. Don't make it any worse please.
|
||||
|
||||
## Highlights, design goals and the `mpaland`->`eyalroz` fork
|
||||
|
||||
If you use a typical libc's `sprintf()` implementation (or similar function), you are likely to pull in a *lot* of unwanted library definitions and can bloat code size - typically by as much as 20 KiB. Now, there is a boatload of so called 'tiny' `printf()`-family implementations around. So why this one? Or rather, why [mpaland/printf](https://github.com/mpaland/printf), and then why this fork?
|
||||
|
||||
Well, Marco Paland tried out many of the available `printf()` implementations, but was disappointed: Some are not thread-safe; some have indirect dependencies on libc or other libraries, making them inconvenient to build and larger when compiled; some only offer extremely limited flag and specifier support; and some produce non-standard-compiled output, failing many tests no found in the repository's test suite.
|
||||
|
||||
Marco therefore decided to write his own implementation, with the following goals in mind (I've dropped a few relative to his original description):
|
||||
|
||||
- Very small implementation
|
||||
- NO dependencies on other packages or libraries; no multiple compiled objects, just one object file.
|
||||
- Support for all standard specifiers and flags, and all width and precision sub-specifiers (see below).
|
||||
- Support of decimal/floating number representation (with an internal, relatively fast `itoa`/`ftoa` implementation)
|
||||
- Reentrancy and thread-safety; `malloc()` freeness.
|
||||
- Clean, robust code.
|
||||
- Extensive test coverage.
|
||||
- MIT license
|
||||
|
||||
Marco's repository upheld most of these goals - but did not quite make it all of the way. As of mid-2021, it still had many C-standard-non-compliance bugs; the test suite was quite lacking in coverage; some goals were simply discarded (like avoiding global/local-static constants) etc. The repository had become quite popular, but unfortunately, Marco had been otherwise preoccupied; he had not really touched the code in the two years prior; many bug reports were pending, and so were many pull requests from eary adopters who had fixed some of the bugs they had encountered.
|
||||
|
||||
The author/maintainer of this fork, Eyal, was one of the latecoming bug-reporters-and-PR-authors; and when noticing nothing was moving forward, decided to take up the same goals (sans the discarded ones); and integrate the existing forks and available PRs into a single "consensus fork" which would continue where Marco had left off. Along the way, numerous other issues and bugs were observed; the build system was improved; the test suite streamlined and expanded; and other contributors also lent a hand (especially [@mickjc750](https://github.com/mickjc750/)). We are now very close to fully realizing the project goals.
|
||||
|
||||
## Using the `printf` library in your project
|
||||
|
||||
There are multiple alternative ways to use `printf` in your own project; the bulleted items below are never _consecutive_, only _alternative_.
|
||||
|
||||
**Use involving CMake:**
|
||||
|
||||
* Use CMake to configure, build and install the library. Then, in another CMake project, use `find_package(printf)` and make sure the library's install location is in CMake's package search path.
|
||||
* Use CMake to configure and build the library. This results in the following files:
|
||||
|
||||
* An object code library file (named `printf.a`, or `printf.so`, or `printf.dll` depending on your platform and choice of static vs dynamic linking)
|
||||
* A header file named `printf.h`
|
||||
* (Not strictly necessary) An optional extra header file `printf_config.h` with the build configuration details.
|
||||
|
||||
Now, in your project, include `printf.h` and link against the library file, you're all set: There are no dependencies to satisfy or keep track of.
|
||||
* Use CMake's `FetchContent` module to obtain the project source code and make it part of your own project's build, e.g.:
|
||||
```
|
||||
FetchContent_Declare(printf_library
|
||||
GIT_REPOSITORY https://github.com/eyalroz/printf.git
|
||||
GIT_TAG v12.34.45 # Replace this with a real available version
|
||||
)
|
||||
FetchContent_MakeAvailable(printf_library)
|
||||
```
|
||||
|
||||
**Use not involving CMake:**
|
||||
|
||||
* Copy `printf.c` and `printf.h` into your own project, and compile the source however you see fit.
|
||||
* Include the contents of `printf.c` into your own code - which can be either C or C++
|
||||
|
||||
Whichever way you choose to use the library:
|
||||
|
||||
* You can have this library stand-in for the C standard library's `printf()` family of functions, e.g. provide `snprintf()` instead of `snprintf_()`, by setting an appropriate [preprocessor definition](#cmake-options-and-preprocessor-definitions) during compilation and use.
|
||||
* Speaking of the [preprocessor definitions](#cmake-options-and-preprocessor-definitions) which affect the library's behavior - you have to be consistent in their choice when building and when using the library. (The easiest way to do that is just not to change any of them and accept the reasonable defaults.)
|
||||
* Two of the functions --- `printf_()` and `vprintf_()` --- will only be usable if you implement a `putchar_(char c)` function to underlie them.
|
||||
* **Avoid `sprintf()` in favor of `snprintf()` for safety and security** - and that goes for the standard C library `sprintf()` as well:. `sprintf()` is unaware of the amount of memory allocated for the string it writes into, and will "happily" overflow your buffer; instead of calling it, pass your buffer size to `snprintf()` - and avoid overflow.
|
||||
|
||||
Finally, if you've started using the library in a publicly-available (FOSS or commercial) project, please consider emailing [@eyalroz](https://github.com/eyalroz), or open an [issue](https://github.com/eyalroz/printf/issues/), to announce this.
|
||||
|
||||
### CMake options and preprocessor definitions
|
||||
|
||||
Options used both in CMake and in the library source code via a preprocessor define:
|
||||
|
||||
| Option name | Default | Description |
|
||||
|----------------------------------------|---------|--------------|
|
||||
| PRINTF_ALIAS_STANDARD_FUNCTION_NAMES | NONE | Alias the standard library function names (`printf()`, `sprintf()` etc.) to the library's functions.<br>The possible values are `NONE`, `SOFT` and `HARD`. With Soft aliasing, the library's object files contain symbols which do not clash with the standard library's: `printf_`, `sprintd_` etc; and a macro in `printf.h` replaces usages of `printf()`, `sprintf()` etc. with the underscored versions. With Hard aliasing, no such macro is used, and the library's object files contain `printf`, `sprintf` etc. - and thus cannot be linked together with a full-fledged standard library. **Note:** The preprocessort definitions `#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT` and `#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_HARD` should be defined to have the same values when using the library as when having compiled the list. |
|
||||
| PRINTF_INTEGER_BUFFER_SIZE | 32 | ntoa (integer) conversion buffer size. This must be big enough to hold one converted numeric number _including_ leading zeros, normally 32 is a sufficient value. Created on the stack. |
|
||||
| PRINTF_DECIMAL_BUFFER_SIZE | 32 | ftoa (float) conversion buffer size. This must be big enough to hold one converted float number _including_ leading zeros, normally 32 is a sufficient value. Created on the stack. |
|
||||
| PRINTF_DEFAULT_FLOAT_PRECISION | 6 | Define the default floating point precision digits |
|
||||
| PRINTF_MAX_INTEGRAL_DIGITS_FOR_DECIMAL | 9 | Maximum number of integral-part digits of a floating-point value for which printing with %f uses decimal (non-exponential) notation |
|
||||
| PRINTF_SUPPORT_DECIMAL_SPECIFIERS | YES | Support decimal notation floating-point conversion specifiers (%f, %F) |
|
||||
| PRINTF_SUPPORT_EXPONENTIAL_SPECIFIERS | YES | Support exponential floating point format conversion specifiers (%e, %E, %g, %G) |
|
||||
| SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS | YES | Support the 'I' + bit size integer specifiers (%I8, %I16, %I32, %I64) as in Microsoft Visual C++ |
|
||||
| PRINTF_SUPPORT_WRITEBACK_SPECIFIER | YES | Support the length write-back specifier (%n) |
|
||||
| PRINTF_SUPPORT_LONG_LONG | YES | Support long long integral types (allows for the ll length modifier and affects %p) |
|
||||
| PRINTF_USE_DOUBLE_INTERNALLY | YES | Use the `double` for internal floating-point calculations (rather than using the single-precision `float` type |
|
||||
|
||||
Within CMake, these options lack the `PRINTF_` prefix.
|
||||
|
||||
CMake-only options:
|
||||
|
||||
| Option name | Default | Description |
|
||||
|----------------------------------------|---------|--------------|
|
||||
| PRINTF_BUILD_STATIC_LIBRARY | NO | Build a library out of a shared object (dynamically linked at load time) rather than a static one (baked into the executables you build) |
|
||||
|
||||
Source-only options:
|
||||
|
||||
| Option name | Default | Description |
|
||||
|----------------------------------------|---------|--------------|
|
||||
| PRINTF_INCLUDE_CONFIG_H | NO | Triggers inclusing by `printf.c` of a "printf_config.h" file, which in turn contains the values of all of the CMake-and-preprocessor options above. A CMake build of the library uses this mechanism to apply the user's choice of options, so it can't have the mechanism itself as an option. |
|
||||
|
||||
Note: The preprocessor definitions are taken into account when compiling `printf.c`, _not_ when using the compiled library by including `printf.h`.
|
||||
|
||||
|
||||
### Reducing compiled code size
|
||||
|
||||
The library's accompanying `CMakeLists.txt` does not set any special optimization flags. If you'd like to benefit from `libprintf` actually being small - you would need to your `CFLAGS` and `LDFLAGS` environment variables appropriately. For example, with GCC, consider:
|
||||
|
||||
* Compiling with `-Os` to make the compiler directly optimize for size.
|
||||
* Compiling with `-ffunction-sections -fdata-sections` and linking with `-WL,--gc-sections`, so that each function and piece of data gets a distinct sections, and discarded if it isn't used.
|
||||
|
||||
You would also be advised to turn off all CMake options for printf functionality you don't actually need (listed in the [previous subsection](#cmake-options-and-preprocessor-definitions) above); and to consider [stripping](https://unix.stackexchange.com/q/2969/34868) the resulting executable.
|
||||
|
||||
|
||||
|
||||
## Library API
|
||||
|
||||
### Implemented functions
|
||||
|
||||
The library offers the following, with the same signatures as in the standard C library (plus an extra underscore):
|
||||
```
|
||||
int printf_(const char* format, ...);
|
||||
int sprintf_(char* s, const char* format, ...);
|
||||
int vsprintf_(char* s, const char* format, va_list arg);
|
||||
int snprintf_(char* s, size_t n, const char* format, ...);
|
||||
int vsnprintf_(char* s, size_t n, const char* format, va_list arg);
|
||||
int vprintf_(const char* format, va_list arg);
|
||||
```
|
||||
Note that `printf_()` and `vprintf_()` don't actually write anything on their own: In addition to their parameters, they will be expecting to find a lower-level `putchar_()` function which they can call for actual printing - and you must provide its implementation, for them to link with. This is part of this library's independence: It is isolated from dealing with console/serial output, files etc.
|
||||
|
||||
Two additional functions are provided by the library beyond those available in the standard library:
|
||||
```
|
||||
int fctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, ...);
|
||||
int vfctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, va_list arg);
|
||||
```
|
||||
These higher-order functions allow for better flexibility of use: You can decide to do different things with the individual output characters: Encode them, compress them, filter them, append them to a buffer or a file, or just discard them. This is achieved by you passing a pointer to your own state information - through `(v)fctprintf()` and all the way to your own `out()` function.
|
||||
|
||||
#### "... but I don't like the underscore-suffix names :-("
|
||||
|
||||
You can [configure](#CMake-options-and-preprocessor-definitions) the library to alias the standard library's names, in which case it exposes `printf()`, `sprintf()`, `vsprintf()` and so on.
|
||||
|
||||
If you alias the standard library function names, *be careful of GCC/clang's `printf()` optimizations!*: GCC and clang recognize patterns such as `printf("%s", str)` or `printf("%c", ch)`, and perform a "strength reduction" of sorts by invoking `puts(stdout, str)` or `putchar(ch)`. If you enable the `PRINTF_ALIAS_STANDARD_FUNCTION_NAMES` option (see below), and do not ensure your code is compiled with the `-fno-builtin-printf` option - you might inadvertantly pull in the standard library implementation - either succeeding and depending on it, or failing with a linker error. When using `printf` as a CMake imported target, that should already be arranged for, but again: Double-check.
|
||||
|
||||
<br>
|
||||
|
||||
Alternatively, you can write short wrappers with your preferred names. This is completely trivial with the v-functions, e.g.:
|
||||
```
|
||||
int my_vprintf(const char* format, va_list va)
|
||||
{
|
||||
return vprintf_(format, va);
|
||||
}
|
||||
```
|
||||
and is still pretty straightforward with the variable-number-of-arguments functions:
|
||||
```
|
||||
int my_sprintf(char* buffer, const char* format, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, format);
|
||||
const int ret = vsprintf_(buffer, format, va);
|
||||
va_end(va);
|
||||
return ret;
|
||||
}
|
||||
```
|
||||
|
||||
### Supported Format Specifiers
|
||||
|
||||
A format specifier follows this prototype: `%[flags][width][.precision][length]type`
|
||||
The following format specifiers are supported:
|
||||
|
||||
#### Types
|
||||
|
||||
| Type | Output |
|
||||
|------------|--------------------------|
|
||||
| `d` or `i` | Signed decimal integer |
|
||||
| `u` | Unsigned decimal integer |
|
||||
| `b` | Unsigned binary |
|
||||
| `o` | Unsigned octal |
|
||||
| `x` | Unsigned hexadecimal integer (lowercase) |
|
||||
| `X` | Unsigned hexadecimal integer (uppercase) |
|
||||
| `f` or `F` | Decimal floating point |
|
||||
| `e` or `E` | Scientific-notation (exponential) floating point |
|
||||
| `g` or `G` | Scientific or decimal floating point |
|
||||
| `c` | Single character |
|
||||
| `s` | String of characters |
|
||||
| `p` | Pointer address |
|
||||
| `n` | None; number of characters produced so far written to argument pointer |
|
||||
|
||||
Notes:
|
||||
|
||||
* The `%a` specifier for hexadecimal floating-point notation (introduced in C99 and C++11) is _not_ currently supported.
|
||||
* If you want to print the percent sign (`%`, US-ASCII character 37), use "%%" in your format string.
|
||||
* The C standard library's `printf()`-style functions don't accept `float` arguments, only `double`'s; that is true for this library as well. `float`'s get converted to `double`'s.
|
||||
|
||||
#### Flags
|
||||
|
||||
| Flags | Description |
|
||||
|---------|-------------|
|
||||
| `-` | Left-justify within the given field width; Right justification is the default. |
|
||||
| `+` | Forces to precede the result with a plus or minus sign (+ or -) even for positive numbers.<br>By default, only negative numbers are preceded with a - sign. |
|
||||
| (space) | If no sign is going to be written, a blank space is inserted before the value. |
|
||||
| `#` | Used with o, b, x or X specifiers the value is preceded with 0, 0b, 0x or 0X respectively for values different than zero.<br>Used with f, F it forces the written output to contain a decimal point even if no more digits follow. By default, if no digits follow, no decimal point is written. |
|
||||
| `0` | Left-pads the number with zeros (0) instead of spaces when padding is specified (see width sub-specifier). |
|
||||
|
||||
|
||||
#### Width Specifiers
|
||||
|
||||
| Width | Description |
|
||||
|----------|-------------|
|
||||
| (number) | Minimum number of characters to be printed. If the value to be printed is shorter than this number, the result is padded with blank spaces. The value is not truncated even if the result is larger. |
|
||||
| `*` | The width is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted. |
|
||||
|
||||
|
||||
#### Precision Specifiers
|
||||
|
||||
| Precision | Description |
|
||||
|-------------|-------------|
|
||||
| `.`(number) | For integer specifiers (d, i, o, u, x, X): precision specifies the minimum number of digits to be written. If the value to be written is shorter than this number, the result is padded with leading zeros. The value is not truncated even if the result is longer. A precision of 0 means that no character is written for the value 0.<br>For f and F specifiers: this is the number of digits to be printed after the decimal point. **By default, this is 6, and a maximum is defined when building the library**.<br>For s: this is the maximum number of characters to be printed. By default all characters are printed until the ending null character is encountered.<br>If the period is specified without an explicit value for precision, 0 is assumed. |
|
||||
| `.*` | The precision is not specified in the format string, but as an additional integer value argument preceding the argument that has to be formatted. |
|
||||
|
||||
|
||||
#### Length modifiers
|
||||
|
||||
The length sub-specifier modifies the length of the data type.
|
||||
|
||||
| Length | With `d`, `i` | With `u`,`o`,`x`, `X` | Support enabled by... |
|
||||
|----------|-----------------------------|--------------------------|---------------------------------------|
|
||||
| (none) | `int` | `unsigned int` | |
|
||||
| `hh` | `signed char` | `unsigned char` | |
|
||||
| `h` | `short int` | `unsigned short int` | |
|
||||
| `l` | `long int` | `unsigned long int` | |
|
||||
| `ll` | `long long int` | `unsigned long long int` | PRINTF_SUPPORT_LONG_LONG |
|
||||
| `j` | `intmax_t` | `uintmax_t` | |
|
||||
| `z` | signed version of `size_t` | `size_t` | |
|
||||
| `t` | `ptrdiff_t` | `ptrdiff_t` | |
|
||||
| `I8` | `int8_t` | `uint8_t` | SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS |
|
||||
| `I16` | `int16_t` | `uint16_t` | SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS |
|
||||
| `I32` | `int32_t` | `uint32_t` | SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS |
|
||||
| `I64` | `int64_t` | `uint64_t` | SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS |
|
||||
|
||||
|
||||
Notes:
|
||||
|
||||
* The `L` modifier, for `long double`, is not currently supported.
|
||||
* A `"%zd"` or `"%zi"` takes a signed integer of the same size as `size_t`.
|
||||
* The implementation currently assumes `intmax_t` has the same size as either `long int` or `long long int`. If this is not the case for your platform, please open an issue.
|
||||
* The `Ixx` length modifiers are not in the C (nor C++) standard, but are somewhat popular, as it makes it easier to handle integer types of specific size. One must specify the argument size in bits immediately after the `I`. The printing is "integer-promotion-safe", i.e. the fact that an `int8_t` may actually be passed in promoted into a larger `int` will not prevent it from being printed using its original value.
|
||||
|
||||
### Return Value
|
||||
|
||||
Upon successful return, all functions return the number of characters written, _excluding_ the terminating NUL character used to end the string.
|
||||
Functions `snprintf()` and `vsnprintf()` don't write more than `count` bytes, including the terminating NUL character ('\0').
|
||||
Anyway, if the output was truncated due to this limit, the return value is the number of characters that _could_ have been written.
|
||||
Notice that a value equal or larger than `count` indicates a truncation. Only when the returned value is non-negative and less than `count`,
|
||||
the string has been completely written with a terminating NUL.
|
||||
If any error is encountered, `-1` is returned.
|
||||
|
||||
If `NULL` is passed for the `buffer` parameter, nothing is written, but the formatted length is returned. For example:
|
||||
```C
|
||||
int length = sprintf(NULL, "Hello, world"); // length is set to 12
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
The following assumes Marco Paland's original repository remains mostly-inactive in terms of commits.
|
||||
|
||||
0. Give this repository a :star: (even if you've already starred the original repository).
|
||||
1. Create an [issue](https://github.com/eyalroz/issues) and describe your idea. Make sure it is in line with the library's design goals.
|
||||
2. Fork the repository
|
||||
3. Create your feature branch (`git checkout -b my-new-feature`).
|
||||
4. Implement your feature/idea; don't forget to make sure all existing tests still pass.
|
||||
5. Add new checks or test-cases to the test suite - both for any problems you have identified and for any new functionality you have introduced.
|
||||
4. Commit your changes (`git commit -a -m "Added some feature"`)
|
||||
5. Publish the branch (`git push origin my-new-feature`)
|
||||
6. Create a new pull request against this repository. Note: Please don't create a PR without a related issue.
|
||||
|
||||
I try to attend to issues and PRs promptly.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
This library is published under the terms of the [MIT license](http://www.opensource.org/licenses/MIT).
|
||||
|
||||
21
src/main.c
21
src/main.c
@@ -208,8 +208,11 @@ sstream_drop:
|
||||
|
||||
scc_ast2ir_ctx_t ast2ir_ctx;
|
||||
#include <abi/win_x64_type_abi.h>
|
||||
scc_ast2ir_ctx_init(&ast2ir_ctx, scc_win_x64_type_abi);
|
||||
scc_ir_cprog_t cprog;
|
||||
scc_ir_cprog_init(&cprog);
|
||||
scc_ast2ir_ctx_init(&ast2ir_ctx, scc_win_x64_type_abi, &cprog);
|
||||
scc_ast2ir_translation_unit(&ast2ir_ctx, translation_unit);
|
||||
scc_ast2ir_ctx_drop(&ast2ir_ctx);
|
||||
|
||||
if (config.emit_ir) {
|
||||
scc_ir_dump_ctx_t ir_dump_ctx;
|
||||
@@ -221,21 +224,21 @@ sstream_drop:
|
||||
scc_tree_dump_ctx_init(&tree_dump, false, (void *)scc_fprintf,
|
||||
(void *)fp);
|
||||
}
|
||||
scc_ir_dump_ctx_init(&ir_dump_ctx, &tree_dump,
|
||||
&ast2ir_ctx.builder.cprog,
|
||||
&ast2ir_ctx.builder.ctx);
|
||||
scc_ir_dump_ctx_init(&ir_dump_ctx, &tree_dump, &cprog);
|
||||
// scc_ir_dump_cprog(&ir_dump_ctx);
|
||||
scc_ir_dump_cprog_linear(&ir_dump_ctx);
|
||||
scc_tree_dump_ctx_drop(&tree_dump);
|
||||
return 0;
|
||||
}
|
||||
|
||||
scc_ir2mcode_ctx_t mcode_ctx;
|
||||
scc_ir2mcode_init(&mcode_ctx, &ast2ir_ctx.builder.cprog,
|
||||
&ast2ir_ctx.builder.ctx, SCC_MCODE_ARCH_AMD64);
|
||||
scc_ir2mcode(&mcode_ctx);
|
||||
scc_ir2mcode_ctx_t ir2mcode_ctx;
|
||||
sccf_builder_t sccf_builder;
|
||||
scc_ir2mcode_init(&ir2mcode_ctx, &cprog, &sccf_builder,
|
||||
SCC_MCODE_ARCH_AMD64);
|
||||
scc_ir2mcode(&ir2mcode_ctx);
|
||||
scc_ir2mcode_drop(&ir2mcode_ctx);
|
||||
|
||||
const sccf_t *sccf = sccf_builder_to_sccf(&mcode_ctx.builder);
|
||||
const sccf_t *sccf = sccf_builder_to_sccf(&sccf_builder);
|
||||
scc_pe_builder_t pe_builder;
|
||||
sccf2pe(&pe_builder, sccf);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from pprint import PrettyPrinter
|
||||
import subprocess
|
||||
import os
|
||||
from pathlib import Path
|
||||
import tomllib
|
||||
import uuid
|
||||
|
||||
# 配置参数
|
||||
WORKSPACE = Path(__file__).resolve().parent # 测试工作目录
|
||||
@@ -29,30 +29,51 @@ def run_command(cmd, capture_output=True):
|
||||
|
||||
def run_test(test_file, expected):
|
||||
print(f"\nTesting {test_file}...")
|
||||
|
||||
|
||||
# 使用唯一文件名避免并发冲突
|
||||
unique_id = str(uuid.uuid4())[:8] # 简短的唯一标识符
|
||||
exe_filename = f"test_{unique_id}.exe"
|
||||
exe_path = WORKSPACE / exe_filename
|
||||
|
||||
# 1. 编译
|
||||
compile_cmd = [str(CC_PATH), str(test_file), "-o", "test.exe"]
|
||||
compile_cmd = [str(CC_PATH), str(test_file), "-o", exe_filename]
|
||||
# 编译时关注 stderr 和返回码
|
||||
_, compile_err, compile_ret = run_command(compile_cmd)
|
||||
|
||||
exe_path = WORKSPACE / "test.exe"
|
||||
|
||||
if not exe_path.exists() or compile_ret != 0:
|
||||
print(f" Compilation failed: {compile_err}")
|
||||
# 确保清理失败的输出文件
|
||||
if exe_path.exists():
|
||||
try:
|
||||
exe_path.unlink()
|
||||
except:
|
||||
pass # 忽略清理失败
|
||||
return False
|
||||
|
||||
# 2. 执行虚拟机并获取输出
|
||||
vm_cmd = [str(exe_path)]
|
||||
actual_output, vm_err, vm_ret = run_command(vm_cmd)
|
||||
|
||||
|
||||
# 如果存在 stderr 且返回码异常(例如负数表示信号终止),则视为运行时错误
|
||||
if vm_err and vm_ret < 0:
|
||||
print(f" Runtime error: {vm_err}")
|
||||
# 清理文件后返回
|
||||
try:
|
||||
exe_path.unlink()
|
||||
except:
|
||||
pass # 忽略清理失败
|
||||
return False
|
||||
|
||||
# 3. 获取返回值 (修改进程返回值而非 stdout)
|
||||
actual = vm_ret
|
||||
|
||||
# 4. 验证结果
|
||||
# 4. 清理输出文件
|
||||
try:
|
||||
exe_path.unlink()
|
||||
except:
|
||||
pass # 忽略清理失败
|
||||
|
||||
# 5. 验证结果
|
||||
# 注意:toml 中读取的 expected 可能是整数,actual 也是整数,直接比较
|
||||
if actual == expected:
|
||||
print(f" PASSED {test_file}")
|
||||
@@ -79,13 +100,8 @@ def main():
|
||||
total += 1
|
||||
if run_test(TEST_DIR / test_file, expected):
|
||||
passed += 1
|
||||
|
||||
# 清理中间文件
|
||||
exe_path = WORKSPACE / "test.exe"
|
||||
if exe_path.exists():
|
||||
os.remove(exe_path)
|
||||
|
||||
print(f"\nTest Summary: {passed}/{total} passed")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
|
||||
Reference in New Issue
Block a user