mirror of
https://github.com/ziglang/zig.git
synced 2026-02-20 08:14:48 +00:00
IR: implement compileVar builtin and more
* implicit array to slice cast * fix if statements at global scope * implement array type IR
This commit is contained in:
parent
19037014e5
commit
8a81f8aa13
@ -1451,6 +1451,7 @@ enum IrInstructionId {
|
||||
IrInstructionIdArrayType,
|
||||
IrInstructionIdSliceType,
|
||||
IrInstructionIdAsm,
|
||||
IrInstructionIdCompileVar,
|
||||
};
|
||||
|
||||
struct IrInstruction {
|
||||
@ -1735,6 +1736,12 @@ struct IrInstructionAsm {
|
||||
bool has_side_effects;
|
||||
};
|
||||
|
||||
struct IrInstructionCompileVar {
|
||||
IrInstruction base;
|
||||
|
||||
IrInstruction *name;
|
||||
};
|
||||
|
||||
enum LValPurpose {
|
||||
LValPurposeNone,
|
||||
LValPurposeAssign,
|
||||
|
||||
@ -869,12 +869,9 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo
|
||||
return result;
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_type_expr_pointer_only(CodeGen *g, ImportTableEntry *import,
|
||||
BlockContext *context, AstNode *node, bool pointer_only)
|
||||
static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
AstNode *node)
|
||||
{
|
||||
if (pointer_only)
|
||||
zig_panic("TODO");
|
||||
|
||||
IrInstruction *result = analyze_const_value(g, context, node, g->builtin_types.entry_type);
|
||||
if (result->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return g->builtin_types.entry_invalid;
|
||||
@ -883,13 +880,6 @@ static TypeTableEntry *analyze_type_expr_pointer_only(CodeGen *g, ImportTableEnt
|
||||
return result->static_value.data.x_type;
|
||||
}
|
||||
|
||||
// Calls analyze_expression on node, and then resolve_type.
|
||||
static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
AstNode *node)
|
||||
{
|
||||
return analyze_type_expr_pointer_only(g, import, context, node, false);
|
||||
}
|
||||
|
||||
static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) {
|
||||
assert(fn_table_entry);
|
||||
AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;
|
||||
|
||||
@ -696,7 +696,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
fprintf(ar->f, ") ");
|
||||
render_node_grouped(ar, node->data.if_bool_expr.then_block);
|
||||
if (node->data.if_bool_expr.else_node) {
|
||||
fprintf(ar->f, "else ");
|
||||
fprintf(ar->f, " else ");
|
||||
render_node_grouped(ar, node->data.if_bool_expr.else_node);
|
||||
}
|
||||
break;
|
||||
|
||||
251
src/codegen.cpp
251
src/codegen.cpp
@ -526,240 +526,6 @@ static LLVMValueRef gen_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddS
|
||||
return result;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
|
||||
LLVMValueRef val1, LLVMValueRef val2)
|
||||
{
|
||||
// for unsigned left shifting, we do the wrapping shift, then logically shift
|
||||
// right the same number of bits
|
||||
// if the values don't match, we have an overflow
|
||||
// for signed left shifting we do the same except arithmetic shift right
|
||||
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
|
||||
LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
|
||||
LLVMValueRef orig_val;
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
orig_val = LLVMBuildAShr(g->builder, result, val2, "");
|
||||
} else {
|
||||
orig_val = LLVMBuildLShr(g->builder, result, val2, "");
|
||||
}
|
||||
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
|
||||
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
gen_debug_safety_crash(g);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
return result;
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
|
||||
TypeTableEntry *type_entry, bool exact)
|
||||
{
|
||||
|
||||
if (want_debug_safety(g, source_node)) {
|
||||
LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
|
||||
LLVMValueRef is_zero_bit;
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, "");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
|
||||
LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
gen_debug_safety_crash(g);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
}
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
assert(!exact);
|
||||
return LLVMBuildFDiv(g->builder, val1, val2, "");
|
||||
}
|
||||
|
||||
assert(type_entry->id == TypeTableEntryIdInt);
|
||||
|
||||
if (exact) {
|
||||
if (want_debug_safety(g, source_node)) {
|
||||
LLVMValueRef remainder_val;
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
remainder_val = LLVMBuildSRem(g->builder, val1, val2, "");
|
||||
} else {
|
||||
remainder_val = LLVMBuildURem(g->builder, val1, val2, "");
|
||||
}
|
||||
LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
|
||||
LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
|
||||
|
||||
LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk");
|
||||
LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail");
|
||||
LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
gen_debug_safety_crash(g);
|
||||
|
||||
LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
}
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMBuildExactSDiv(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return ZigLLVMBuildExactUDiv(g->builder, val1, val2, "");
|
||||
}
|
||||
} else {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMBuildSDiv(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return LLVMBuildUDiv(g->builder, val1, val2, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
|
||||
LLVMValueRef val1, LLVMValueRef val2,
|
||||
TypeTableEntry *op1_type, TypeTableEntry *op2_type,
|
||||
BinOpType bin_op)
|
||||
{
|
||||
assert(op1_type == op2_type);
|
||||
|
||||
switch (bin_op) {
|
||||
case BinOpTypeBinOr:
|
||||
case BinOpTypeAssignBitOr:
|
||||
return LLVMBuildOr(g->builder, val1, val2, "");
|
||||
case BinOpTypeBinXor:
|
||||
case BinOpTypeAssignBitXor:
|
||||
return LLVMBuildXor(g->builder, val1, val2, "");
|
||||
case BinOpTypeBinAnd:
|
||||
case BinOpTypeAssignBitAnd:
|
||||
return LLVMBuildAnd(g->builder, val1, val2, "");
|
||||
case BinOpTypeBitShiftLeft:
|
||||
case BinOpTypeBitShiftLeftWrap:
|
||||
case BinOpTypeAssignBitShiftLeft:
|
||||
case BinOpTypeAssignBitShiftLeftWrap:
|
||||
{
|
||||
assert(op1_type->id == TypeTableEntryIdInt);
|
||||
bool is_wrapping = (bin_op == BinOpTypeBitShiftLeftWrap) ||
|
||||
(bin_op == BinOpTypeAssignBitShiftLeftWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildShl(g->builder, val1, val2, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
return gen_overflow_shl_op(g, op1_type, val1, val2);
|
||||
} else if (op1_type->data.integral.is_signed) {
|
||||
return ZigLLVMBuildNSWShl(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return ZigLLVMBuildNUWShl(g->builder, val1, val2, "");
|
||||
}
|
||||
}
|
||||
case BinOpTypeBitShiftRight:
|
||||
case BinOpTypeAssignBitShiftRight:
|
||||
assert(op1_type->id == TypeTableEntryIdInt);
|
||||
assert(op2_type->id == TypeTableEntryIdInt);
|
||||
|
||||
if (op1_type->data.integral.is_signed) {
|
||||
return LLVMBuildAShr(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return LLVMBuildLShr(g->builder, val1, val2, "");
|
||||
}
|
||||
case BinOpTypeAdd:
|
||||
case BinOpTypeAddWrap:
|
||||
case BinOpTypeAssignPlus:
|
||||
case BinOpTypeAssignPlusWrap:
|
||||
if (op1_type->id == TypeTableEntryIdFloat) {
|
||||
return LLVMBuildFAdd(g->builder, val1, val2, "");
|
||||
} else if (op1_type->id == TypeTableEntryIdInt) {
|
||||
bool is_wrapping = (bin_op == BinOpTypeAddWrap) || (bin_op == BinOpTypeAssignPlusWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildAdd(g->builder, val1, val2, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
return gen_overflow_op(g, op1_type, AddSubMulAdd, val1, val2);
|
||||
} else if (op1_type->data.integral.is_signed) {
|
||||
return LLVMBuildNSWAdd(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return LLVMBuildNUWAdd(g->builder, val1, val2, "");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
case BinOpTypeSub:
|
||||
case BinOpTypeSubWrap:
|
||||
case BinOpTypeAssignMinus:
|
||||
case BinOpTypeAssignMinusWrap:
|
||||
if (op1_type->id == TypeTableEntryIdFloat) {
|
||||
return LLVMBuildFSub(g->builder, val1, val2, "");
|
||||
} else if (op1_type->id == TypeTableEntryIdInt) {
|
||||
bool is_wrapping = (bin_op == BinOpTypeSubWrap || bin_op == BinOpTypeAssignMinusWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildSub(g->builder, val1, val2, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
return gen_overflow_op(g, op1_type, AddSubMulSub, val1, val2);
|
||||
} else if (op1_type->data.integral.is_signed) {
|
||||
return LLVMBuildNSWSub(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return LLVMBuildNUWSub(g->builder, val1, val2, "");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
case BinOpTypeMult:
|
||||
case BinOpTypeMultWrap:
|
||||
case BinOpTypeAssignTimes:
|
||||
case BinOpTypeAssignTimesWrap:
|
||||
if (op1_type->id == TypeTableEntryIdFloat) {
|
||||
return LLVMBuildFMul(g->builder, val1, val2, "");
|
||||
} else if (op1_type->id == TypeTableEntryIdInt) {
|
||||
bool is_wrapping = (bin_op == BinOpTypeMultWrap || bin_op == BinOpTypeAssignTimesWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildMul(g->builder, val1, val2, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
return gen_overflow_op(g, op1_type, AddSubMulMul, val1, val2);
|
||||
} else if (op1_type->data.integral.is_signed) {
|
||||
return LLVMBuildNSWMul(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return LLVMBuildNUWMul(g->builder, val1, val2, "");
|
||||
}
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
case BinOpTypeDiv:
|
||||
case BinOpTypeAssignDiv:
|
||||
return gen_div(g, source_node, val1, val2, op1_type, false);
|
||||
case BinOpTypeMod:
|
||||
case BinOpTypeAssignMod:
|
||||
if (op1_type->id == TypeTableEntryIdFloat) {
|
||||
return LLVMBuildFRem(g->builder, val1, val2, "");
|
||||
} else {
|
||||
assert(op1_type->id == TypeTableEntryIdInt);
|
||||
if (op1_type->data.integral.is_signed) {
|
||||
return LLVMBuildSRem(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return LLVMBuildURem(g->builder, val1, val2, "");
|
||||
}
|
||||
}
|
||||
case BinOpTypeBoolOr:
|
||||
case BinOpTypeBoolAnd:
|
||||
case BinOpTypeCmpEq:
|
||||
case BinOpTypeCmpNotEq:
|
||||
case BinOpTypeCmpLessThan:
|
||||
case BinOpTypeCmpGreaterThan:
|
||||
case BinOpTypeCmpLessOrEq:
|
||||
case BinOpTypeCmpGreaterOrEq:
|
||||
case BinOpTypeInvalid:
|
||||
case BinOpTypeAssign:
|
||||
case BinOpTypeAssignBoolAnd:
|
||||
case BinOpTypeAssignBoolOr:
|
||||
case BinOpTypeUnwrapMaybe:
|
||||
case BinOpTypeArrayCat:
|
||||
case BinOpTypeArrayMult:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
static LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) {
|
||||
switch (cmp_op) {
|
||||
case IrBinOpCmpEq:
|
||||
@ -825,7 +591,7 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef
|
||||
return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
|
||||
static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node,
|
||||
LLVMValueRef target_ref, LLVMValueRef value,
|
||||
TypeTableEntry *op1_type, TypeTableEntry *op2_type)
|
||||
{
|
||||
@ -834,18 +600,10 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b
|
||||
}
|
||||
if (handle_is_ptr(op1_type)) {
|
||||
assert(op1_type == op2_type);
|
||||
assert(bin_op == BinOpTypeAssign);
|
||||
|
||||
return gen_struct_memcpy(g, value, target_ref, op1_type);
|
||||
}
|
||||
|
||||
if (bin_op != BinOpTypeAssign) {
|
||||
assert(source_node->type == NodeTypeBinOpExpr);
|
||||
LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");
|
||||
|
||||
value = gen_arithmetic_bin_op(g, source_node, left_value, value, op1_type, op2_type, bin_op);
|
||||
}
|
||||
|
||||
LLVMBuildStore(g->builder, value, target_ref);
|
||||
return nullptr;
|
||||
}
|
||||
@ -1036,7 +794,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
||||
return expr_val;
|
||||
} else {
|
||||
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 0, "");
|
||||
gen_assign_raw(g, cast_instruction->base.source_node, BinOpTypeAssign,
|
||||
gen_assign_raw(g, cast_instruction->base.source_node,
|
||||
val_ptr, expr_val, child_type, actual_type);
|
||||
|
||||
LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");
|
||||
@ -1065,7 +823,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
|
||||
LLVMBuildStore(g->builder, ok_err_val, err_tag_ptr);
|
||||
|
||||
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, 1, "");
|
||||
gen_assign_raw(g, cast_instruction->base.source_node, BinOpTypeAssign,
|
||||
gen_assign_raw(g, cast_instruction->base.source_node,
|
||||
payload_ptr, expr_val, child_type, actual_type);
|
||||
|
||||
return cast_instruction->tmp_ptr;
|
||||
@ -1414,7 +1172,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable,
|
||||
want_zeroes = true;
|
||||
|
||||
if (have_init_expr) {
|
||||
gen_assign_raw(g, init_value->source_node, BinOpTypeAssign, var->value_ref,
|
||||
gen_assign_raw(g, init_value->source_node, var->value_ref,
|
||||
ir_llvm_value(g, init_value), var->type, init_value->type_entry);
|
||||
} else {
|
||||
bool ignore_uninit = false;
|
||||
@ -1685,6 +1443,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdSetDebugSafety:
|
||||
case IrInstructionIdArrayType:
|
||||
case IrInstructionIdSliceType:
|
||||
case IrInstructionIdCompileVar:
|
||||
zig_unreachable();
|
||||
case IrInstructionIdReturn:
|
||||
return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
|
||||
|
||||
19
src/eval.cpp
19
src/eval.cpp
@ -318,8 +318,23 @@ void eval_const_expr_implicit_cast(CastOp cast_op,
|
||||
// can't do it
|
||||
break;
|
||||
case CastOpToUnknownSizeArray:
|
||||
zig_panic("TODO compile time implicit to unknown size array");
|
||||
break;
|
||||
{
|
||||
assert(other_type->id == TypeTableEntryIdArray);
|
||||
assert(other_val->data.x_array.size == other_type->data.array.len);
|
||||
|
||||
const_val->data.x_struct.fields = allocate<ConstExprValue>(2);
|
||||
ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index];
|
||||
ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index];
|
||||
|
||||
ptr_field->special = ConstValSpecialStatic;
|
||||
ptr_field->data.x_ptr.base_ptr = other_val;
|
||||
|
||||
len_field->special = ConstValSpecialStatic;
|
||||
bignum_init_unsigned(&len_field->data.x_bignum, other_type->data.array.len);
|
||||
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
break;
|
||||
}
|
||||
case CastOpMaybeWrap:
|
||||
const_val->data.x_maybe = other_val;
|
||||
const_val->special = ConstValSpecialStatic;
|
||||
|
||||
471
src/ir.cpp
471
src/ir.cpp
@ -218,6 +218,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAsm *) {
|
||||
return IrInstructionIdAsm;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileVar *) {
|
||||
return IrInstructionIdCompileVar;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
|
||||
T *special_instruction = allocate<T>(1);
|
||||
@ -507,14 +511,6 @@ static IrInstruction *ir_build_field_ptr(IrBuilder *irb, AstNode *source_node,
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
//static IrInstruction *ir_build_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction,
|
||||
// IrInstruction *container_ptr, Buf *field_name)
|
||||
//{
|
||||
// IrInstruction *new_instruction = ir_build_field_ptr(irb, old_instruction->source_node, container_ptr, field_name);
|
||||
// ir_link_new_instruction(new_instruction, old_instruction);
|
||||
// return new_instruction;
|
||||
//}
|
||||
|
||||
static IrInstruction *ir_build_read_field(IrBuilder *irb, AstNode *source_node,
|
||||
IrInstruction *container_ptr, Buf *field_name)
|
||||
{
|
||||
@ -527,14 +523,6 @@ static IrInstruction *ir_build_read_field(IrBuilder *irb, AstNode *source_node,
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
//static IrInstruction *ir_build_read_field_from(IrBuilder *irb, IrInstruction *old_instruction,
|
||||
// IrInstruction *container_ptr, Buf *field_name)
|
||||
//{
|
||||
// IrInstruction *new_instruction = ir_build_read_field(irb, old_instruction->source_node, container_ptr, field_name);
|
||||
// ir_link_new_instruction(new_instruction, old_instruction);
|
||||
// return new_instruction;
|
||||
//}
|
||||
|
||||
static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, AstNode *source_node,
|
||||
IrInstruction *struct_ptr, TypeStructField *field)
|
||||
{
|
||||
@ -861,6 +849,15 @@ static IrInstruction *ir_build_asm_from(IrBuilder *irb, IrInstruction *old_instr
|
||||
return new_instruction;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_compile_var(IrBuilder *irb, AstNode *source_node, IrInstruction *name) {
|
||||
IrInstructionCompileVar *instruction = ir_build_instruction<IrInstructionCompileVar>(irb, source_node);
|
||||
instruction->name = name;
|
||||
|
||||
ir_ref_instruction(name);
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block,
|
||||
bool gen_error_defers, bool gen_maybe_defers)
|
||||
{
|
||||
@ -1336,6 +1333,15 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
|
||||
|
||||
return ir_build_set_debug_safety(irb, node, arg0_value, arg1_value);
|
||||
}
|
||||
case BuiltinFnIdCompileVar:
|
||||
{
|
||||
AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
|
||||
IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, node->block_context);
|
||||
if (arg0_value == irb->codegen->invalid_instruction)
|
||||
return arg0_value;
|
||||
|
||||
return ir_build_compile_var(irb, node, arg0_value);
|
||||
}
|
||||
case BuiltinFnIdMemcpy:
|
||||
case BuiltinFnIdMemset:
|
||||
case BuiltinFnIdSizeof:
|
||||
@ -1350,7 +1356,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) {
|
||||
case BuiltinFnIdCInclude:
|
||||
case BuiltinFnIdCDefine:
|
||||
case BuiltinFnIdCUndef:
|
||||
case BuiltinFnIdCompileVar:
|
||||
case BuiltinFnIdCompileErr:
|
||||
case BuiltinFnIdConstEval:
|
||||
case BuiltinFnIdCtz:
|
||||
@ -1410,14 +1415,15 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) {
|
||||
IrBasicBlock *else_block = ir_build_basic_block(irb, "Else");
|
||||
IrBasicBlock *endif_block = ir_build_basic_block(irb, "EndIf");
|
||||
|
||||
ir_build_cond_br(irb, condition->source_node, condition, then_block, else_block, false);
|
||||
bool is_inline = (node->block_context->fn_entry == nullptr);
|
||||
ir_build_cond_br(irb, condition->source_node, condition, then_block, else_block, is_inline);
|
||||
|
||||
ir_set_cursor_at_end(irb, then_block);
|
||||
IrInstruction *then_expr_result = ir_gen_node(irb, then_node, node->block_context);
|
||||
if (then_expr_result == irb->codegen->invalid_instruction)
|
||||
return then_expr_result;
|
||||
IrBasicBlock *after_then_block = irb->current_basic_block;
|
||||
ir_build_br(irb, node, endif_block, false);
|
||||
ir_build_br(irb, node, endif_block, is_inline);
|
||||
|
||||
ir_set_cursor_at_end(irb, else_block);
|
||||
IrInstruction *else_expr_result;
|
||||
@ -1429,7 +1435,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) {
|
||||
else_expr_result = ir_build_const_void(irb, node);
|
||||
}
|
||||
IrBasicBlock *after_else_block = irb->current_basic_block;
|
||||
ir_build_br(irb, node, endif_block, false);
|
||||
ir_build_br(irb, node, endif_block, is_inline);
|
||||
|
||||
ir_set_cursor_at_end(irb, endif_block);
|
||||
IrInstruction **incoming_values = allocate<IrInstruction *>(2);
|
||||
@ -2281,7 +2287,19 @@ static TypeTableEntry *ir_analyze_const_usize(IrAnalyze *ira, IrInstruction *ins
|
||||
return ira->codegen->builtin_types.entry_usize;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
|
||||
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) {
|
||||
if (value->static_value.special != ConstValSpecialStatic) {
|
||||
add_node_error(ira->codegen, value->source_node,
|
||||
buf_sprintf("unable to evaluate constant expression"));
|
||||
return nullptr;
|
||||
}
|
||||
return &value->static_value;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_resolve_type_lval(IrAnalyze *ira, IrInstruction *type_value, LValPurpose lval) {
|
||||
if (lval != LValPurposeNone)
|
||||
zig_panic("TODO");
|
||||
|
||||
if (type_value == ira->codegen->invalid_instruction)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
@ -2294,44 +2312,15 @@ static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
ConstExprValue *const_val = &type_value->static_value;
|
||||
if (const_val->special == ConstValSpecialRuntime) {
|
||||
add_node_error(ira->codegen, type_value->source_node,
|
||||
buf_sprintf("unable to evaluate constant expression"));
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, type_value);
|
||||
if (!const_val)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
return const_val->data.x_type;
|
||||
}
|
||||
|
||||
static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value) {
|
||||
if (value->static_value.special != ConstValSpecialStatic) {
|
||||
add_node_error(ira->codegen, value->source_node,
|
||||
buf_sprintf("unable to evaluate constant expression"));
|
||||
return nullptr;
|
||||
}
|
||||
return &value->static_value;
|
||||
}
|
||||
|
||||
static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *bool_value, bool *out) {
|
||||
if (bool_value == ira->codegen->invalid_instruction)
|
||||
return false;
|
||||
|
||||
if (bool_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return false;
|
||||
|
||||
if (bool_value->type_entry->id != TypeTableEntryIdBool) {
|
||||
add_node_error(ira->codegen, bool_value->source_node,
|
||||
buf_sprintf("expected type 'bool', found '%s'", buf_ptr(&bool_value->type_entry->name)));
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, bool_value);
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = const_val->data.x_bool;
|
||||
return true;
|
||||
static TypeTableEntry *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) {
|
||||
return ir_resolve_type_lval(ira, type_value, LValPurposeNone);
|
||||
}
|
||||
|
||||
static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
|
||||
@ -2347,12 +2336,9 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ConstExprValue *const_val = &fn_value->static_value;
|
||||
if (const_val->special == ConstValSpecialRuntime) {
|
||||
add_node_error(ira->codegen, fn_value->source_node,
|
||||
buf_sprintf("unable to evaluate constant expression"));
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, fn_value);
|
||||
if (!const_val)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return const_val->data.x_fn;
|
||||
}
|
||||
@ -2654,6 +2640,69 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value,
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) {
|
||||
if (value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return false;
|
||||
|
||||
IrInstruction *casted_value = ir_get_casted_value(ira, value, ira->codegen->builtin_types.entry_usize);
|
||||
if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return false;
|
||||
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, casted_value);
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = const_val->data.x_bignum.data.x_uint;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool ir_resolve_bool(IrAnalyze *ira, IrInstruction *value, bool *out) {
|
||||
if (value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return false;
|
||||
|
||||
IrInstruction *casted_value = ir_get_casted_value(ira, value, ira->codegen->builtin_types.entry_bool);
|
||||
if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return false;
|
||||
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, casted_value);
|
||||
if (!const_val)
|
||||
return false;
|
||||
|
||||
*out = const_val->data.x_bool;
|
||||
return true;
|
||||
}
|
||||
|
||||
static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) {
|
||||
if (value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return nullptr;
|
||||
|
||||
TypeTableEntry *str_type = get_slice_type(ira->codegen, ira->codegen->builtin_types.entry_u8, true);
|
||||
IrInstruction *casted_value = ir_get_casted_value(ira, value, str_type);
|
||||
if (casted_value->type_entry->id == TypeTableEntryIdInvalid)
|
||||
return nullptr;
|
||||
|
||||
ConstExprValue *const_val = ir_resolve_const(ira, casted_value);
|
||||
if (!const_val)
|
||||
return nullptr;
|
||||
|
||||
ConstExprValue *ptr_field = &const_val->data.x_struct.fields[slice_ptr_index];
|
||||
ConstExprValue *len_field = &const_val->data.x_struct.fields[slice_len_index];
|
||||
ConstExprValue *array_val = ptr_field->data.x_ptr.base_ptr;
|
||||
assert(ptr_field->data.x_ptr.index != SIZE_MAX);
|
||||
size_t len = len_field->data.x_bignum.data.x_uint;
|
||||
Buf *result = buf_alloc();
|
||||
buf_resize(result, len);
|
||||
for (size_t i = 0; i < len; i += 1) {
|
||||
size_t new_index = ptr_field->data.x_ptr.index + i;
|
||||
ConstExprValue *char_val = &array_val->data.x_array.elements[new_index];
|
||||
uint64_t big_c = char_val->data.x_bignum.data.x_uint;
|
||||
assert(big_c <= UINT8_MAX);
|
||||
uint8_t c = big_c;
|
||||
buf_ptr(result)[i] = c;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_return(IrAnalyze *ira,
|
||||
IrInstructionReturn *return_instruction)
|
||||
{
|
||||
@ -3528,29 +3577,33 @@ static TypeTableEntry *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructionCondBr *cond_br_instruction) {
|
||||
TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
|
||||
IrInstruction *condition = ir_get_casted_value(ira, cond_br_instruction->condition->other, bool_type);
|
||||
if (condition == ira->codegen->invalid_instruction)
|
||||
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
|
||||
IrInstruction *condition = cond_br_instruction->condition->other;
|
||||
|
||||
// TODO detect backward jumps
|
||||
if (condition->static_value.special != ConstValSpecialRuntime) {
|
||||
IrBasicBlock *old_dest_block = condition->static_value.data.x_bool ?
|
||||
|
||||
if (cond_br_instruction->is_inline || condition->static_value.special != ConstValSpecialRuntime) {
|
||||
bool cond_is_true;
|
||||
if (!ir_resolve_bool(ira, condition, &cond_is_true))
|
||||
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
|
||||
|
||||
IrBasicBlock *old_dest_block = cond_is_true ?
|
||||
cond_br_instruction->then_block : cond_br_instruction->else_block;
|
||||
|
||||
if (cond_br_instruction->is_inline || old_dest_block->ref_count == 1) {
|
||||
ir_inline_bb(ira, old_dest_block);
|
||||
return ira->codegen->builtin_types.entry_unreachable;
|
||||
}
|
||||
} else if (cond_br_instruction->is_inline) {
|
||||
add_node_error(ira->codegen, condition->source_node,
|
||||
buf_sprintf("unable to evaluate constant expression"));
|
||||
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
|
||||
}
|
||||
|
||||
TypeTableEntry *bool_type = ira->codegen->builtin_types.entry_bool;
|
||||
IrInstruction *casted_condition = ir_get_casted_value(ira, condition, bool_type);
|
||||
if (casted_condition == ira->codegen->invalid_instruction)
|
||||
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
|
||||
|
||||
IrBasicBlock *new_then_block = ir_get_new_bb(ira, cond_br_instruction->then_block);
|
||||
IrBasicBlock *new_else_block = ir_get_new_bb(ira, cond_br_instruction->else_block);
|
||||
ir_build_cond_br_from(&ira->new_irb, &cond_br_instruction->base, condition, new_then_block, new_else_block, false);
|
||||
ir_build_cond_br_from(&ira->new_irb, &cond_br_instruction->base,
|
||||
casted_condition, new_then_block, new_else_block, false);
|
||||
return ir_finish_anal(ira, ira->codegen->builtin_types.entry_unreachable);
|
||||
}
|
||||
|
||||
@ -4255,6 +4308,100 @@ static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionA
|
||||
return return_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira,
|
||||
IrInstructionArrayType *array_type_instruction)
|
||||
{
|
||||
IrInstruction *size_value = array_type_instruction->size->other;
|
||||
uint64_t size;
|
||||
if (!ir_resolve_usize(ira, size_value, &size))
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
IrInstruction *child_type_value = array_type_instruction->child_type->other;
|
||||
TypeTableEntry *child_type = ir_resolve_type(ira, child_type_value);
|
||||
TypeTableEntry *canon_child_type = get_underlying_type(child_type);
|
||||
switch (canon_child_type->id) {
|
||||
case TypeTableEntryIdTypeDecl:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdInvalid:
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
case TypeTableEntryIdVar:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdUndefLit:
|
||||
case TypeTableEntryIdNullLit:
|
||||
case TypeTableEntryIdBlock:
|
||||
add_node_error(ira->codegen, array_type_instruction->base.source_node,
|
||||
buf_sprintf("array of type '%s' not allowed", buf_ptr(&child_type->name)));
|
||||
// TODO if this is a typedecl, add error note showing the declaration of the type decl
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdBool:
|
||||
case TypeTableEntryIdInt:
|
||||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdErrorUnion:
|
||||
case TypeTableEntryIdPureError:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdUnion:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdNamespace:
|
||||
case TypeTableEntryIdGenericFn:
|
||||
{
|
||||
TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size);
|
||||
bool depends_on_compile_var = child_type_value->static_value.depends_on_compile_var ||
|
||||
size_value->static_value.depends_on_compile_var;
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &array_type_instruction->base,
|
||||
depends_on_compile_var);
|
||||
out_val->data.x_type = result_type;
|
||||
return ira->codegen->builtin_types.entry_type;
|
||||
}
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_compile_var(IrAnalyze *ira,
|
||||
IrInstructionCompileVar *compile_var_instruction)
|
||||
{
|
||||
IrInstruction *name_value = compile_var_instruction->name->other;
|
||||
Buf *var_name = ir_resolve_str(ira, name_value);
|
||||
if (!var_name)
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
|
||||
ConstExprValue *out_val = ir_build_const_from(ira, &compile_var_instruction->base, true);
|
||||
if (buf_eql_str(var_name, "is_big_endian")) {
|
||||
out_val->data.x_bool = ira->codegen->is_big_endian;
|
||||
return ira->codegen->builtin_types.entry_bool;
|
||||
} else if (buf_eql_str(var_name, "is_release")) {
|
||||
out_val->data.x_bool = ira->codegen->is_release_build;
|
||||
return ira->codegen->builtin_types.entry_bool;
|
||||
} else if (buf_eql_str(var_name, "is_test")) {
|
||||
out_val->data.x_bool = ira->codegen->is_test_build;
|
||||
return ira->codegen->builtin_types.entry_bool;
|
||||
} else if (buf_eql_str(var_name, "os")) {
|
||||
out_val->data.x_enum.tag = ira->codegen->target_os_index;
|
||||
return ira->codegen->builtin_types.entry_os_enum;
|
||||
} else if (buf_eql_str(var_name, "arch")) {
|
||||
out_val->data.x_enum.tag = ira->codegen->target_arch_index;
|
||||
return ira->codegen->builtin_types.entry_arch_enum;
|
||||
} else if (buf_eql_str(var_name, "environ")) {
|
||||
out_val->data.x_enum.tag = ira->codegen->target_environ_index;
|
||||
return ira->codegen->builtin_types.entry_environ_enum;
|
||||
} else if (buf_eql_str(var_name, "object_format")) {
|
||||
out_val->data.x_enum.tag = ira->codegen->target_oformat_index;
|
||||
return ira->codegen->builtin_types.entry_oformat_enum;
|
||||
} else {
|
||||
add_node_error(ira->codegen, name_value->source_node,
|
||||
buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
|
||||
return ira->codegen->builtin_types.entry_invalid;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
|
||||
switch (instruction->id) {
|
||||
case IrInstructionIdInvalid:
|
||||
@ -4305,12 +4452,15 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
|
||||
return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
|
||||
case IrInstructionIdAsm:
|
||||
return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
|
||||
case IrInstructionIdArrayType:
|
||||
return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
|
||||
case IrInstructionIdCompileVar:
|
||||
return ir_analyze_instruction_compile_var(ira, (IrInstructionCompileVar *)instruction);
|
||||
case IrInstructionIdSwitchBr:
|
||||
case IrInstructionIdCast:
|
||||
case IrInstructionIdContainerInitList:
|
||||
case IrInstructionIdContainerInitFields:
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
case IrInstructionIdArrayType:
|
||||
zig_panic("TODO analyze more instructions");
|
||||
}
|
||||
zig_unreachable();
|
||||
@ -4414,6 +4564,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdStructFieldPtr:
|
||||
case IrInstructionIdArrayType:
|
||||
case IrInstructionIdSliceType:
|
||||
case IrInstructionIdCompileVar:
|
||||
return false;
|
||||
case IrInstructionIdAsm:
|
||||
{
|
||||
@ -5180,43 +5331,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
|
||||
// case BuiltinFnIdCUndef:
|
||||
// zig_panic("TODO");
|
||||
//
|
||||
// case BuiltinFnIdCompileVar:
|
||||
// {
|
||||
// AstNode **str_node = node->data.fn_call_expr.params.at(0)->parent_field;
|
||||
//
|
||||
// Buf *var_name = resolve_const_expr_str(g, import, context, str_node);
|
||||
// if (!var_name) {
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
//
|
||||
// ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
// const_val->ok = true;
|
||||
// const_val->depends_on_compile_var = true;
|
||||
//
|
||||
// if (buf_eql_str(var_name, "is_big_endian")) {
|
||||
// return resolve_expr_const_val_as_bool(g, node, g->is_big_endian, true);
|
||||
// } else if (buf_eql_str(var_name, "is_release")) {
|
||||
// return resolve_expr_const_val_as_bool(g, node, g->is_release_build, true);
|
||||
// } else if (buf_eql_str(var_name, "is_test")) {
|
||||
// return resolve_expr_const_val_as_bool(g, node, g->is_test_build, true);
|
||||
// } else if (buf_eql_str(var_name, "os")) {
|
||||
// const_val->data.x_enum.tag = g->target_os_index;
|
||||
// return g->builtin_types.entry_os_enum;
|
||||
// } else if (buf_eql_str(var_name, "arch")) {
|
||||
// const_val->data.x_enum.tag = g->target_arch_index;
|
||||
// return g->builtin_types.entry_arch_enum;
|
||||
// } else if (buf_eql_str(var_name, "environ")) {
|
||||
// const_val->data.x_enum.tag = g->target_environ_index;
|
||||
// return g->builtin_types.entry_environ_enum;
|
||||
// } else if (buf_eql_str(var_name, "object_format")) {
|
||||
// const_val->data.x_enum.tag = g->target_oformat_index;
|
||||
// return g->builtin_types.entry_oformat_enum;
|
||||
// } else {
|
||||
// add_node_error(g, *str_node,
|
||||
// buf_sprintf("unrecognized compile variable: '%s'", buf_ptr(var_name)));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
// }
|
||||
// case BuiltinFnIdConstEval:
|
||||
// {
|
||||
// AstNode **expr_node = node->data.fn_call_expr.params.at(0)->parent_field;
|
||||
@ -7605,53 +7719,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) {
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
// TypeTableEntry *expected_type, AstNode *node)
|
||||
//{
|
||||
// AstNode *size_node = node->data.array_type.size;
|
||||
//
|
||||
// TypeTableEntry *child_type = analyze_type_expr_pointer_only(g, import, context,
|
||||
// node->data.array_type.child_type, true);
|
||||
//
|
||||
// if (child_type->id == TypeTableEntryIdUnreachable) {
|
||||
// add_node_error(g, node, buf_create_from_str("array of unreachable not allowed"));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// } else if (child_type->id == TypeTableEntryIdInvalid) {
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
//
|
||||
// if (size_node) {
|
||||
// child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type);
|
||||
// TypeTableEntry *size_type = analyze_expression(g, import, context,
|
||||
// g->builtin_types.entry_usize, size_node);
|
||||
// if (size_type->id == TypeTableEntryIdInvalid) {
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
//
|
||||
// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
|
||||
// if (const_val->ok) {
|
||||
// if (const_val->data.x_bignum.is_negative) {
|
||||
// add_node_error(g, size_node,
|
||||
// buf_sprintf("array size %s is negative",
|
||||
// buf_ptr(bignum_to_buf(&const_val->data.x_bignum))));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// } else {
|
||||
// return resolve_expr_const_val_as_type(g, node,
|
||||
// get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint), false);
|
||||
// }
|
||||
// } else if (context->fn_entry) {
|
||||
// return resolve_expr_const_val_as_type(g, node,
|
||||
// get_slice_type(g, child_type, node->data.array_type.is_const), false);
|
||||
// } else {
|
||||
// add_node_error(g, first_executing_node(size_node),
|
||||
// buf_sprintf("unable to evaluate constant expression"));
|
||||
// return g->builtin_types.entry_invalid;
|
||||
// }
|
||||
// } else {
|
||||
// TypeTableEntry *slice_type = get_slice_type(g, child_type, node->data.array_type.is_const);
|
||||
// return resolve_expr_const_val_as_type(g, node, slice_type, false);
|
||||
// }
|
||||
//}
|
||||
//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) {
|
||||
// size_t result = 0;
|
||||
// while (inner_block != outer_block) {
|
||||
@ -9572,3 +9639,97 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no
|
||||
// LLVMPositionBuilderAtEnd(g->builder, basic_block);
|
||||
// return nullptr;
|
||||
//}
|
||||
//static LLVMValueRef gen_overflow_shl_op(CodeGen *g, TypeTableEntry *type_entry,
|
||||
// LLVMValueRef val1, LLVMValueRef val2)
|
||||
//{
|
||||
// // for unsigned left shifting, we do the wrapping shift, then logically shift
|
||||
// // right the same number of bits
|
||||
// // if the values don't match, we have an overflow
|
||||
// // for signed left shifting we do the same except arithmetic shift right
|
||||
//
|
||||
// assert(type_entry->id == TypeTableEntryIdInt);
|
||||
//
|
||||
// LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, "");
|
||||
// LLVMValueRef orig_val;
|
||||
// if (type_entry->data.integral.is_signed) {
|
||||
// orig_val = LLVMBuildAShr(g->builder, result, val2, "");
|
||||
// } else {
|
||||
// orig_val = LLVMBuildLShr(g->builder, result, val2, "");
|
||||
// }
|
||||
// LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val1, orig_val, "");
|
||||
//
|
||||
// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowOk");
|
||||
// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "OverflowFail");
|
||||
// LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
// gen_debug_safety_crash(g);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
// return result;
|
||||
//}
|
||||
//
|
||||
//static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2,
|
||||
// TypeTableEntry *type_entry, bool exact)
|
||||
//{
|
||||
//
|
||||
// if (want_debug_safety(g, source_node)) {
|
||||
// LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
|
||||
// LLVMValueRef is_zero_bit;
|
||||
// if (type_entry->id == TypeTableEntryIdInt) {
|
||||
// is_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, val2, zero, "");
|
||||
// } else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
// is_zero_bit = LLVMBuildFCmp(g->builder, LLVMRealOEQ, val2, zero, "");
|
||||
// } else {
|
||||
// zig_unreachable();
|
||||
// }
|
||||
// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroOk");
|
||||
// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivZeroFail");
|
||||
// LLVMBuildCondBr(g->builder, is_zero_bit, fail_block, ok_block);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
// gen_debug_safety_crash(g);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
// }
|
||||
//
|
||||
// if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
// assert(!exact);
|
||||
// return LLVMBuildFDiv(g->builder, val1, val2, "");
|
||||
// }
|
||||
//
|
||||
// assert(type_entry->id == TypeTableEntryIdInt);
|
||||
//
|
||||
// if (exact) {
|
||||
// if (want_debug_safety(g, source_node)) {
|
||||
// LLVMValueRef remainder_val;
|
||||
// if (type_entry->data.integral.is_signed) {
|
||||
// remainder_val = LLVMBuildSRem(g->builder, val1, val2, "");
|
||||
// } else {
|
||||
// remainder_val = LLVMBuildURem(g->builder, val1, val2, "");
|
||||
// }
|
||||
// LLVMValueRef zero = LLVMConstNull(type_entry->type_ref);
|
||||
// LLVMValueRef ok_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, remainder_val, zero, "");
|
||||
//
|
||||
// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactOk");
|
||||
// LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "DivExactFail");
|
||||
// LLVMBuildCondBr(g->builder, ok_bit, ok_block, fail_block);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, fail_block);
|
||||
// gen_debug_safety_crash(g);
|
||||
//
|
||||
// LLVMPositionBuilderAtEnd(g->builder, ok_block);
|
||||
// }
|
||||
// if (type_entry->data.integral.is_signed) {
|
||||
// return LLVMBuildExactSDiv(g->builder, val1, val2, "");
|
||||
// } else {
|
||||
// return ZigLLVMBuildExactUDiv(g->builder, val1, val2, "");
|
||||
// }
|
||||
// } else {
|
||||
// if (type_entry->data.integral.is_signed) {
|
||||
// return LLVMBuildSDiv(g->builder, val1, val2, "");
|
||||
// } else {
|
||||
// return LLVMBuildUDiv(g->builder, val1, val2, "");
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@ -472,6 +472,12 @@ static void ir_print_asm(IrPrint *irp, IrInstructionAsm *instruction) {
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_compile_var(IrPrint *irp, IrInstructionCompileVar *instruction) {
|
||||
fprintf(irp->f, "@compileVar(");
|
||||
ir_print_other_instruction(irp, instruction->name);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
ir_print_prefix(irp, instruction);
|
||||
switch (instruction->id) {
|
||||
@ -561,6 +567,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
|
||||
case IrInstructionIdAsm:
|
||||
ir_print_asm(irp, (IrInstructionAsm *)instruction);
|
||||
break;
|
||||
case IrInstructionIdCompileVar:
|
||||
ir_print_compile_var(irp, (IrInstructionCompileVar *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSwitchBr:
|
||||
zig_panic("TODO print more IR instructions");
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user