Sema: introduce all_vector_instructions backend feature

Sema is arbitrarily scalarizing some operations, which means that when I
try to implement vectorized versions of those operations in a backend,
they are impossible to test due to Sema not producing them. Now, I can
implement them and then temporarily enable the new feature for that
backend in order to test them. Once the backend supports all of them,
the feature can be permanently enabled.

This also deletes the Air instructions `int_from_bool` and
`int_from_ptr`, which are just bitcasts with a fixed result type, since
changing `un_op` to `ty_op` takes up the same amount of memory.
This commit is contained in:
Jacob Young
2025-01-30 11:58:32 -05:00
parent 8195b64f57
commit afa74c6b21
17 changed files with 102 additions and 269 deletions

View File

@@ -3325,7 +3325,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.bitcast => try airBitcast(f, inst),
.intcast => try airIntCast(f, inst),
.trunc => try airTrunc(f, inst),
.int_from_bool => try airIntFromBool(f, inst),
.load => try airLoad(f, inst),
.store => try airStore(f, inst, false),
.store_safe => try airStore(f, inst, true),
@@ -3371,8 +3370,6 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.fpext,
=> try airFloatCast(f, inst),
.int_from_ptr => try airIntFromPtr(f, inst),
.atomic_store_unordered => try airAtomicStore(f, inst, toMemoryOrder(.unordered)),
.atomic_store_monotonic => try airAtomicStore(f, inst, toMemoryOrder(.monotonic)),
.atomic_store_release => try airAtomicStore(f, inst, toMemoryOrder(.release)),
@@ -3983,21 +3980,6 @@ fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
fn airIntFromBool(f: *Function, inst: Air.Inst.Index) !CValue {
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try f.resolveInst(un_op);
try reap(f, inst, &.{un_op});
const writer = f.object.writer();
const inst_ty = f.typeOfIndex(inst);
const local = try f.allocLocal(inst, inst_ty);
const a = try Assignment.start(f, writer, try f.ctypeFromType(inst_ty, .complete));
try f.writeCValue(writer, local, .Other);
try a.assign(f, writer);
try f.writeCValue(writer, operand, .Other);
try a.end(f, writer);
return local;
}
fn airStore(f: *Function, inst: Air.Inst.Index, safety: bool) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
@@ -4970,7 +4952,7 @@ fn bitcast(f: *Function, dest_ty: Type, operand: CValue, operand_ty: Type) !CVal
src_info.bits == dest_info.bits) return operand;
}
if (dest_ty.isPtrAtRuntime(zcu) and operand_ty.isPtrAtRuntime(zcu)) {
if (dest_ty.isPtrAtRuntime(zcu) or operand_ty.isPtrAtRuntime(zcu)) {
const local = try f.allocLocal(null, dest_ty);
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = (");
@@ -6455,30 +6437,6 @@ fn airFloatCast(f: *Function, inst: Air.Inst.Index) !CValue {
return local;
}
fn airIntFromPtr(f: *Function, inst: Air.Inst.Index) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
const un_op = f.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try f.resolveInst(un_op);
const operand_ty = f.typeOf(un_op);
try reap(f, inst, &.{un_op});
const inst_ty = f.typeOfIndex(inst);
const writer = f.object.writer();
const local = try f.allocLocal(inst, inst_ty);
try f.writeCValue(writer, local, .Other);
try writer.writeAll(" = (");
try f.renderType(writer, inst_ty);
try writer.writeByte(')');
if (operand_ty.isSlice(zcu))
try f.writeCValueMember(writer, operand, .{ .identifier = "ptr" })
else
try f.writeCValue(writer, operand, .Other);
try writer.writeAll(";\n");
return local;
}
fn airUnBuiltinCall(
f: *Function,
inst: Air.Inst.Index,

View File

@@ -5154,7 +5154,6 @@ pub const FuncGen = struct {
.ret_ptr => try self.airRetPtr(inst),
.arg => try self.airArg(inst),
.bitcast => try self.airBitCast(inst),
.int_from_bool => try self.airIntFromBool(inst),
.breakpoint => try self.airBreakpoint(inst),
.ret_addr => try self.airRetAddr(inst),
.frame_addr => try self.airFrameAddress(inst),
@@ -5167,7 +5166,6 @@ pub const FuncGen = struct {
.trunc => try self.airTrunc(inst),
.fptrunc => try self.airFptrunc(inst),
.fpext => try self.airFpext(inst),
.int_from_ptr => try self.airIntFromPtr(inst),
.load => try self.airLoad(body[i..]),
.not => try self.airNot(inst),
.store => try self.airStore(inst, false),
@@ -9435,16 +9433,6 @@ pub const FuncGen = struct {
}
}
fn airIntFromPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.ng.object;
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.resolveInst(un_op);
const ptr_ty = self.typeOf(un_op);
const operand_ptr = try self.sliceOrArrayPtr(operand, ptr_ty);
const dest_llvm_ty = try o.lowerType(self.typeOfIndex(inst));
return self.wip.cast(.ptrtoint, operand_ptr, dest_llvm_ty, "");
}
fn airBitCast(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand_ty = self.typeOf(ty_op.operand);
@@ -9476,6 +9464,10 @@ pub const FuncGen = struct {
return self.wip.cast(.inttoptr, operand, llvm_dest_ty, "");
}
if (operand_ty.isPtrAtRuntime(zcu) and inst_ty.zigTypeTag(zcu) == .int) {
return self.wip.cast(.ptrtoint, operand, llvm_dest_ty, "");
}
if (operand_ty.zigTypeTag(zcu) == .vector and inst_ty.zigTypeTag(zcu) == .array) {
const elem_ty = operand_ty.childType(zcu);
if (!result_is_ref) {
@@ -9564,12 +9556,6 @@ pub const FuncGen = struct {
return self.wip.cast(.bitcast, operand, llvm_dest_ty, "");
}
fn airIntFromBool(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.resolveInst(un_op);
return operand;
}
fn airArg(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.ng.object;
const pt = o.pt;

View File

@@ -3449,10 +3449,8 @@ const NavGen = struct {
.bitcast => try self.airBitCast(inst),
.intcast, .trunc => try self.airIntCast(inst),
.int_from_ptr => try self.airIntFromPtr(inst),
.float_from_int => try self.airFloatFromInt(inst),
.int_from_float => try self.airIntFromFloat(inst),
.int_from_bool => try self.airIntFromBool(inst),
.fpext, .fptrunc => try self.airFloatCast(inst),
.not => try self.airNot(inst),
@@ -4706,9 +4704,14 @@ const NavGen = struct {
fn airBitCast(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand_id = try self.resolve(ty_op.operand);
const operand_ty = self.typeOf(ty_op.operand);
const result_ty = self.typeOfIndex(inst);
if (operand_ty.toIntern() == .bool_type) {
const operand = try self.temporary(ty_op.operand);
const result = try self.intFromBool(operand);
return try result.materialize(self);
}
const operand_id = try self.resolve(ty_op.operand);
return try self.bitCast(result_ty, operand_ty, operand_id);
}
@@ -4749,12 +4752,6 @@ const NavGen = struct {
return result_id;
}
fn airIntFromPtr(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand_id = try self.resolve(un_op);
return try self.intFromPtr(operand_id);
}
fn airFloatFromInt(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand_ty = self.typeOf(ty_op.operand);
@@ -4808,13 +4805,6 @@ const NavGen = struct {
return result_id;
}
fn airIntFromBool(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const un_op = self.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
const operand = try self.temporary(un_op);
const result = try self.intFromBool(operand);
return try result.materialize(self);
}
fn airFloatCast(self: *NavGen, inst: Air.Inst.Index) !?IdRef {
const ty_op = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
const operand_id = try self.resolve(ty_op.operand);