authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-16 17:23:30+02:00
committergravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2021-10-17 20:33:04+02:00
logd193ba9843324dcaf239220df8db63ebe3adf67e
treed90845ee6808df06d314325e9e85b4395bd8b454
parent9336a87452eda87c19cb707484d0b6dfb4140b57

stage2: array->vector coercion


3 files changed, 75 insertions(+), 22 deletions(-)

src/Sema.zig+29-22
......@@ -11653,7 +11653,11 @@ fn coerce(
1165311653 else => {},
1165411654 },
1165511655 .Array => switch (inst_ty.zigTypeTag()) {
11656 .Vector => return sema.coerceVectorToArray(block, dest_ty, dest_ty_src, inst, inst_src),
11656 .Vector => return sema.coerceVectorInMemory(block, dest_ty, dest_ty_src, inst, inst_src),
11657 else => {},
11658 },
11659 .Vector => switch (inst_ty.zigTypeTag()) {
11660 .Array => return sema.coerceVectorInMemory(block, dest_ty, dest_ty_src, inst, inst_src),
1165711661 else => {},
1165811662 },
1165911663 else => {},
......@@ -12237,46 +12241,49 @@ fn coerceEnumToUnion(
1223712241 return sema.failWithOwnedErrorMsg(msg);
1223812242}
1223912243
12240fn coerceVectorToArray(
12244// Coerces vectors/arrays which have the same in-memory layout. This can be used for
12245// both coercing from and to vectors.
12246fn coerceVectorInMemory(
1224112247 sema: *Sema,
1224212248 block: *Block,
12243 array_ty: Type,
12244 array_ty_src: LazySrcLoc,
12245 vector: Air.Inst.Ref,
12246 vector_src: LazySrcLoc,
12249 dest_ty: Type,
12250 dest_ty_src: LazySrcLoc,
12251 inst: Air.Inst.Ref,
12252 inst_src: LazySrcLoc,
1224712253) !Air.Inst.Ref {
12248 const vector_ty = sema.typeOf(vector);
12249 const array_len = array_ty.arrayLen();
12250 const vector_len = vector_ty.arrayLen();
12251 if (array_len != vector_len) {
12254 const inst_ty = sema.typeOf(inst);
12255 const inst_len = inst_ty.arrayLen();
12256 const dest_len = dest_ty.arrayLen();
12257
12258 if (dest_len != inst_len) {
1225212259 const msg = msg: {
12253 const msg = try sema.errMsg(block, vector_src, "expected {}, found {}", .{
12254 array_ty, vector_ty,
12260 const msg = try sema.errMsg(block, inst_src, "expected {}, found {}", .{
12261 dest_ty, inst_ty,
1225512262 });
1225612263 errdefer msg.destroy(sema.gpa);
12257 try sema.errNote(block, array_ty_src, msg, "array has length {d}", .{array_len});
12258 try sema.errNote(block, vector_src, msg, "vector has length {d}", .{vector_len});
12264 try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len});
12265 try sema.errNote(block, inst_src, msg, "source has length {d}", .{inst_len});
1225912266 break :msg msg;
1226012267 };
1226112268 return sema.failWithOwnedErrorMsg(msg);
1226212269 }
1226312270
1226412271 const target = sema.mod.getTarget();
12265 const array_elem_ty = array_ty.childType();
12266 const vector_elem_ty = vector_ty.childType();
12267 const in_memory_result = coerceInMemoryAllowed(array_elem_ty, vector_elem_ty, false, target);
12272 const dest_elem_ty = dest_ty.childType();
12273 const inst_elem_ty = inst_ty.childType();
12274 const in_memory_result = coerceInMemoryAllowed(dest_elem_ty, inst_elem_ty, false, target);
1226812275 if (in_memory_result != .ok) {
1226912276 // TODO recursive error notes for coerceInMemoryAllowed failure
12270 return sema.fail(block, vector_src, "expected {}, found {}", .{ array_ty, vector_ty });
12277 return sema.fail(block, inst_src, "expected {}, found {}", .{ dest_ty, inst_ty });
1227112278 }
1227212279
12273 if (try sema.resolveMaybeUndefVal(block, vector_src, vector)) |vector_val| {
12280 if (try sema.resolveMaybeUndefVal(block, inst_src, inst)) |inst_val| {
1227412281 // These types share the same comptime value representation.
12275 return sema.addConstant(array_ty, vector_val);
12282 return sema.addConstant(dest_ty, inst_val);
1227612283 }
1227712284
12278 try sema.requireRuntimeBlock(block, vector_src);
12279 return block.addTyOp(.bitcast, array_ty, vector);
12285 try sema.requireRuntimeBlock(block, inst_src);
12286 return block.addTyOp(.bitcast, dest_ty, inst);
1228012287}
1228112288
1228212289fn coerceErrSetToAnyError(
src/codegen/llvm.zig+37
......@@ -2889,6 +2889,43 @@ pub const FuncGen = struct {
28892889 }
28902890 }
28912891 return array_ptr;
2892 } else if (operand_ty.zigTypeTag() == .Array and inst_ty.zigTypeTag() == .Vector) {
2893 const target = self.dg.module.getTarget();
2894 const elem_ty = operand_ty.childType();
2895 const llvm_vector_ty = try self.dg.llvmType(inst_ty);
2896 if (!isByRef(operand_ty)) {
2897 return self.dg.todo("implement bitcast non-ref array to vector", .{});
2898 }
2899
2900 const bitcast_ok = elem_ty.bitSize(target) == elem_ty.abiSize(target) * 8;
2901 if (bitcast_ok) {
2902 const llvm_vector_ptr_ty = llvm_vector_ty.pointerType(0);
2903 const casted_ptr = self.builder.buildBitCast(operand, llvm_vector_ptr_ty, "");
2904 const vector = self.builder.buildLoad(casted_ptr, "");
2905 // The array is aligned to the element's alignment, while the vector might have a completely
2906 // different alignment. This means we need to enforce the alignment of this load.
2907 vector.setAlignment(elem_ty.abiAlignment(target));
2908 return vector;
2909 } else {
2910 // If the ABI size of the element type is not evenly divisible by size in bits;
2911 // a simple bitcast will not work, and we fall back to extractelement.
2912 const llvm_usize = try self.dg.llvmType(Type.usize);
2913 const llvm_u32 = self.context.intType(32);
2914 const zero = llvm_usize.constNull();
2915 const vector_len = operand_ty.arrayLen();
2916 var vector = llvm_vector_ty.getUndef();
2917 var i: u64 = 0;
2918 while (i < vector_len) : (i += 1) {
2919 const index_usize = llvm_usize.constInt(i, .False);
2920 const index_u32 = llvm_u32.constInt(i, .False);
2921 const indexes: [2]*const llvm.Value = .{ zero, index_usize };
2922 const elem_ptr = self.builder.buildInBoundsGEP(operand, &indexes, indexes.len, "");
2923 const elem = self.builder.buildLoad(elem_ptr, "");
2924 vector = self.builder.buildInsertElement(vector, elem, index_u32, "");
2925 }
2926
2927 return vector;
2928 }
28922929 }
28932930
28942931 return self.builder.buildBitCast(operand, llvm_dest_ty, "");
src/codegen/llvm/bindings.zig+9
......@@ -567,6 +567,15 @@ pub const Builder = opaque {
567567 Name: [*:0]const u8,
568568 ) *const Value;
569569
570 pub const buildInsertElement = LLVMBuildInsertElement;
571 extern fn LLVMBuildInsertElement(
572 *const Builder,
573 VecVal: *const Value,
574 EltVal: *const Value,
575 Index: *const Value,
576 Name: [*:0]const u8,
577 ) *const Value;
578
570579 pub const buildPtrToInt = LLVMBuildPtrToInt;
571580 extern fn LLVMBuildPtrToInt(
572581 *const Builder,