Commit 76ad9cb10e
Changed files (7)
src/stage1/all_types.hpp
@@ -95,6 +95,11 @@ enum AddressSpace {
AddressSpaceGS,
AddressSpaceFS,
AddressSpaceSS,
+ AddressSpaceGlobal,
+ AddressSpaceConstant,
+ AddressSpaceParam,
+ AddressSpaceShared,
+ AddressSpaceLocal
};
// This one corresponds to the builtin.zig enum.
@@ -1842,6 +1847,7 @@ enum BuiltinFnId {
BuiltinFnIdMaximum,
BuiltinFnIdMinimum,
BuiltinFnIdPrefetch,
+ BuiltinFnIdAddrSpaceCast,
};
struct BuiltinFnEntry {
@@ -2673,6 +2679,7 @@ enum Stage1ZirInstId : uint8_t {
Stage1ZirInstIdWasmMemoryGrow,
Stage1ZirInstIdSrc,
Stage1ZirInstIdPrefetch,
+ Stage1ZirInstIdAddrSpaceCast,
};
// ir_render_* functions in codegen.cpp consume Gen instructions and produce LLVM IR.
@@ -4169,6 +4176,13 @@ struct Stage1AirInstAlignCast {
Stage1AirInst *target;
};
+struct Stage1ZirInstAddrSpaceCast {
+ Stage1ZirInst base;
+
+ Stage1ZirInst *addrspace;
+ Stage1ZirInst *ptr;
+};
+
struct Stage1ZirInstSetAlignStack {
Stage1ZirInst base;
src/stage1/analyze.cpp
@@ -1030,6 +1030,11 @@ const char *address_space_name(AddressSpace as) {
case AddressSpaceGS: return "gs";
case AddressSpaceFS: return "fs";
case AddressSpaceSS: return "ss";
+ case AddressSpaceGlobal: return "global";
+ case AddressSpaceConstant: return "constant";
+ case AddressSpaceParam: return "param";
+ case AddressSpaceShared: return "shared";
+ case AddressSpaceLocal: return "local";
}
zig_unreachable();
}
src/stage1/astgen.cpp
@@ -351,6 +351,8 @@ void destroy_instruction_src(Stage1ZirInst *inst) {
return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstSrc *>(inst));
case Stage1ZirInstIdPrefetch:
return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstPrefetch *>(inst));
+ case Stage1ZirInstIdAddrSpaceCast:
+ return heap::c_allocator.destroy(reinterpret_cast<Stage1ZirInstAddrSpaceCast *>(inst));
}
zig_unreachable();
}
@@ -947,6 +949,10 @@ static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstPrefetch *) {
return Stage1ZirInstIdPrefetch;
}
+static constexpr Stage1ZirInstId ir_inst_id(Stage1ZirInstAddrSpaceCast *) {
+ return Stage1ZirInstIdAddrSpaceCast;
+}
+
template<typename T>
static T *ir_create_instruction(Stage1AstGen *ag, Scope *scope, AstNode *source_node) {
T *special_instruction = heap::c_allocator.create<T>();
@@ -2572,6 +2578,19 @@ static Stage1ZirInst *ir_build_align_cast_src(Stage1AstGen *ag, Scope *scope, As
return &instruction->base;
}
+static Stage1ZirInst *ir_build_addrspace_cast(Stage1AstGen *ag, Scope *scope, AstNode *source_node,
+ Stage1ZirInst *addrspace, Stage1ZirInst *ptr)
+{
+ Stage1ZirInstAddrSpaceCast *instruction = ir_build_instruction<Stage1ZirInstAddrSpaceCast>(ag, scope, source_node);
+ instruction->addrspace = addrspace;
+ instruction->ptr = ptr;
+
+ ir_ref_instruction(addrspace, ag->current_basic_block);
+ ir_ref_instruction(ptr, ag->current_basic_block);
+
+ return &instruction->base;
+}
+
static Stage1ZirInst *ir_build_resolve_result(Stage1AstGen *ag, Scope *scope, AstNode *source_node,
ResultLoc *result_loc, Stage1ZirInst *ty)
{
@@ -5459,6 +5478,21 @@ static Stage1ZirInst *astgen_builtin_fn_call(Stage1AstGen *ag, Scope *scope, Ast
Stage1ZirInst *ir_extern = ir_build_prefetch(ag, scope, node, ptr_value, casted_options_value);
return ir_lval_wrap(ag, scope, ir_extern, lval, result_loc);
}
+ case BuiltinFnIdAddrSpaceCast:
+ {
+ AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
+ Stage1ZirInst *arg0_value = astgen_node(ag, arg0_node, scope);
+ if (arg0_value == ag->codegen->invalid_inst_src)
+ return arg0_value;
+
+ AstNode* arg1_node = node->data.fn_call_expr.params.at(1);
+ Stage1ZirInst *arg1_value = astgen_node(ag, arg1_node, scope);
+ if (arg1_value == ag->codegen->invalid_inst_src)
+ return arg1_value;
+
+ Stage1ZirInst *addrspace_cast = ir_build_addrspace_cast(ag, scope, node, arg0_value, arg1_value);
+ return ir_lval_wrap(ag, scope, addrspace_cast, lval, result_loc);
+ }
}
zig_unreachable();
}
src/stage1/codegen.cpp
@@ -4371,7 +4371,7 @@ static LLVMValueRef ir_render_binary_not(CodeGen *g, Stage1Air *executable,
static LLVMValueRef gen_soft_float_neg(CodeGen *g, ZigType *operand_type, LLVMValueRef operand) {
uint32_t vector_len = operand_type->id == ZigTypeIdVector ? operand_type->data.vector.len : 0;
- uint16_t num_bits = operand_type->id == ZigTypeIdVector ?
+ uint16_t num_bits = operand_type->id == ZigTypeIdVector ?
operand_type->data.vector.elem_type->data.floating.bit_count :
operand_type->data.floating.bit_count;
@@ -10085,6 +10085,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdMaximum, "maximum", 2);
create_builtin_fn(g, BuiltinFnIdMinimum, "minimum", 2);
create_builtin_fn(g, BuiltinFnIdPrefetch, "prefetch", 2);
+ create_builtin_fn(g, BuiltinFnIdAddrSpaceCast, "addrSpaceCast", 2);
}
static const char *bool_to_str(bool b) {
src/stage1/ir.cpp
@@ -23746,6 +23746,50 @@ static Stage1AirInst *ir_analyze_instruction_align_cast(IrAnalyze *ira, Stage1Zi
return result;
}
+static bool ir_resolve_addrspace(IrAnalyze *ira, Stage1AirInst *value, AddressSpace *out) {
+ if (type_is_invalid(value->value->type))
+ return false;
+
+ ZigType *addrspace_type = get_builtin_type(ira->codegen, "AddressSpace");
+
+ Stage1AirInst *casted_value = ir_implicit_cast(ira, value, addrspace_type);
+ if (type_is_invalid(casted_value->value->type))
+ return false;
+
+ ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad);
+ if (!const_val)
+ return false;
+
+ *out = (AddressSpace)bigint_as_u32(&const_val->data.x_enum_tag);
+ return true;
+}
+
+static Stage1AirInst *ir_analyze_instruction_addrspace_cast(IrAnalyze *ira, Stage1ZirInstAddrSpaceCast *instruction) {
+ Stage1AirInst *ptr_inst = instruction->ptr->child;
+ ZigType *ptr_type = ptr_inst->value->type;
+ if (type_is_invalid(ptr_type))
+ return ira->codegen->invalid_inst_gen;
+
+ AddressSpace addrspace;
+ if (!ir_resolve_addrspace(ira, instruction->addrspace->child, &addrspace))
+ return ira->codegen->invalid_inst_gen;
+
+ if (addrspace != AddressSpaceGeneric) {
+ ir_add_error_node(ira, instruction->addrspace->source_node, buf_sprintf(
+ "address space '%s' not available in stage 1 compiler, must be .generic",
+ address_space_name(addrspace)));
+ return ira->codegen->invalid_inst_gen;
+ }
+
+ if (is_slice(ptr_type) || get_src_ptr_type(ptr_type) != nullptr) {
+ ir_add_error_node(ira, instruction->ptr->source_node,
+ buf_sprintf("expected pointer or slice, found '%s'", buf_ptr(&ptr_type->name)));
+ return ira->codegen->invalid_inst_gen;
+ }
+
+ return ptr_inst;
+}
+
static Stage1AirInst *ir_analyze_instruction_set_align_stack(IrAnalyze *ira, Stage1ZirInstSetAlignStack *instruction) {
uint32_t align_bytes;
Stage1AirInst *align_bytes_inst = instruction->align_bytes->child;
@@ -25451,6 +25495,8 @@ static Stage1AirInst *ir_analyze_instruction_base(IrAnalyze *ira, Stage1ZirInst
return ir_analyze_instruction_src(ira, (Stage1ZirInstSrc *)instruction);
case Stage1ZirInstIdPrefetch:
return ir_analyze_instruction_prefetch(ira, (Stage1ZirInstPrefetch *)instruction);
+ case Stage1ZirInstIdAddrSpaceCast:
+ return ir_analyze_instruction_addrspace_cast(ira, (Stage1ZirInstAddrSpaceCast *)instruction);
}
zig_unreachable();
}
@@ -25832,6 +25878,7 @@ bool ir_inst_src_has_side_effects(Stage1ZirInst *instruction) {
case Stage1ZirInstIdWasmMemorySize:
case Stage1ZirInstIdSrc:
case Stage1ZirInstIdReduce:
+ case Stage1ZirInstIdAddrSpaceCast:
return false;
case Stage1ZirInstIdAsm:
src/stage1/ir_print.cpp
@@ -373,6 +373,8 @@ const char* ir_inst_src_type_str(Stage1ZirInstId id) {
return "SrcSrc";
case Stage1ZirInstIdPrefetch:
return "SrcPrefetch";
+ case Stage1ZirInstIdAddrSpaceCast:
+ return "SrcAddrSpaceCast";
}
zig_unreachable();
}
@@ -2382,6 +2384,14 @@ static void ir_print_align_cast(IrPrintSrc *irp, Stage1ZirInstAlignCast *instruc
fprintf(irp->f, ")");
}
+static void ir_print_addrspace_cast(IrPrintSrc *irp, Stage1ZirInstAddrSpaceCast *instruction) {
+ fprintf(irp->f, "@addrSpaceCast(");
+ ir_print_other_inst_src(irp, instruction->addrspace);
+ fprintf(irp->f, ",");
+ ir_print_other_inst_src(irp, instruction->ptr);
+ fprintf(irp->f, ")");
+}
+
static void ir_print_align_cast(IrPrintGen *irp, Stage1AirInstAlignCast *instruction) {
fprintf(irp->f, "@alignCast(");
ir_print_other_inst_gen(irp, instruction->target);
@@ -3127,6 +3137,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, Stage1ZirInst *instruction, bool
case Stage1ZirInstIdPrefetch:
ir_print_prefetch(irp, (Stage1ZirInstPrefetch *)instruction);
break;
+ case Stage1ZirInstIdAddrSpaceCast:
+ ir_print_addrspace_cast(irp, (Stage1ZirInstAddrSpaceCast *)instruction);
+ break;
}
fprintf(irp->f, "\n");
}
src/Sema.zig
@@ -18181,7 +18181,6 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
const ptr = try sema.resolveInst(extra.rhs);
const ptr_ty = sema.typeOf(ptr);
-
// TODO in addition to pointers, this instruction is supposed to work for
// pointer-like optionals and slices.
try sema.checkPtrOperand(block, ptr_src, ptr_ty);