Commit 76ad9cb10e

Robin Voetter <robin@voetter.nl>
2022-09-17 01:24:13
backport @addrSpaceCast to stage 1
1 parent fb9a7da
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);