| ... | @@ -5466,7 +5466,7 @@ pub const FuncGen = struct { | ... | @@ -5466,7 +5466,7 @@ pub const FuncGen = struct { |
| 5466 | const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod)); | 5466 | const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod)); |
| 5467 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); | 5467 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5468 | | 5468 | |
| 5469 | _ = try self.wip.callIntrinsic(.va_copy, &.{}, &.{ dest_list, src_list }, ""); | 5469 | _ = try self.wip.callIntrinsic(.none, .va_copy, &.{}, &.{ dest_list, src_list }, ""); |
| 5470 | return if (isByRef(va_list_ty, mod)) | 5470 | return if (isByRef(va_list_ty, mod)) |
| 5471 | dest_list | 5471 | dest_list |
| 5472 | else | 5472 | else |
| ... | @@ -5477,7 +5477,7 @@ pub const FuncGen = struct { | ... | @@ -5477,7 +5477,7 @@ pub const FuncGen = struct { |
| 5477 | const un_op = self.air.instructions.items(.data)[inst].un_op; | 5477 | const un_op = self.air.instructions.items(.data)[inst].un_op; |
| 5478 | const src_list = try self.resolveInst(un_op); | 5478 | const src_list = try self.resolveInst(un_op); |
| 5479 | | 5479 | |
| 5480 | _ = try self.wip.callIntrinsic(.va_end, &.{}, &.{src_list}, ""); | 5480 | _ = try self.wip.callIntrinsic(.none, .va_end, &.{}, &.{src_list}, ""); |
| 5481 | return .none; | 5481 | return .none; |
| 5482 | } | 5482 | } |
| 5483 | | 5483 | |
| ... | @@ -5490,7 +5490,7 @@ pub const FuncGen = struct { | ... | @@ -5490,7 +5490,7 @@ pub const FuncGen = struct { |
| 5490 | const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod)); | 5490 | const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod)); |
| 5491 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); | 5491 | const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment); |
| 5492 | | 5492 | |
| 5493 | _ = try self.wip.callIntrinsic(.va_start, &.{}, &.{dest_list}, ""); | 5493 | _ = try self.wip.callIntrinsic(.none, .va_start, &.{}, &.{dest_list}, ""); |
| 5494 | return if (isByRef(va_list_ty, mod)) | 5494 | return if (isByRef(va_list_ty, mod)) |
| 5495 | dest_list | 5495 | dest_list |
| 5496 | else | 5496 | else |
| ... | @@ -5600,8 +5600,8 @@ pub const FuncGen = struct { | ... | @@ -5600,8 +5600,8 @@ pub const FuncGen = struct { |
| 5600 | const both_pl_block_end = self.wip.cursor.block; | 5600 | const both_pl_block_end = self.wip.cursor.block; |
| 5601 | | 5601 | |
| 5602 | self.wip.cursor = .{ .block = end_block }; | 5602 | self.wip.cursor = .{ .block = end_block }; |
| 5603 | const llvm_i1_0 = try o.builder.intValue(.i1, 0); | 5603 | const llvm_i1_0 = Builder.Value.false; |
| 5604 | const llvm_i1_1 = try o.builder.intValue(.i1, 1); | 5604 | const llvm_i1_1 = Builder.Value.true; |
| 5605 | const incoming_values: [3]Builder.Value = .{ | 5605 | const incoming_values: [3]Builder.Value = .{ |
| 5606 | switch (op) { | 5606 | switch (op) { |
| 5607 | .eq => llvm_i1_1, | 5607 | .eq => llvm_i1_1, |
| ... | @@ -5822,7 +5822,7 @@ pub const FuncGen = struct { | ... | @@ -5822,7 +5822,7 @@ pub const FuncGen = struct { |
| 5822 | if (can_elide_load) | 5822 | if (can_elide_load) |
| 5823 | return payload_ptr; | 5823 | return payload_ptr; |
| 5824 | | 5824 | |
| 5825 | return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false); | 5825 | return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); |
| 5826 | } | 5826 | } |
| 5827 | const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset]; | 5827 | const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset]; |
| 5828 | return fg.wip.load(.normal, load_ty, payload_ptr, payload_alignment, ""); | 5828 | return fg.wip.load(.normal, load_ty, payload_ptr, payload_alignment, ""); |
| ... | @@ -6121,7 +6121,7 @@ pub const FuncGen = struct { | ... | @@ -6121,7 +6121,7 @@ pub const FuncGen = struct { |
| 6121 | return ptr; | 6121 | return ptr; |
| 6122 | | 6122 | |
| 6123 | const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); | 6123 | const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); |
| 6124 | return self.loadByRef(ptr, elem_ty, elem_alignment, false); | 6124 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); |
| 6125 | } | 6125 | } |
| 6126 | | 6126 | |
| 6127 | return self.load(ptr, slice_ty); | 6127 | return self.load(ptr, slice_ty); |
| ... | @@ -6161,7 +6161,7 @@ pub const FuncGen = struct { | ... | @@ -6161,7 +6161,7 @@ pub const FuncGen = struct { |
| 6161 | try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, ""); | 6161 | try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, ""); |
| 6162 | if (canElideLoad(self, body_tail)) return elem_ptr; | 6162 | if (canElideLoad(self, body_tail)) return elem_ptr; |
| 6163 | const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); | 6163 | const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); |
| 6164 | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, false); | 6164 | return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal); |
| 6165 | } else { | 6165 | } else { |
| 6166 | const elem_llvm_ty = try o.lowerType(elem_ty); | 6166 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| 6167 | if (Air.refToIndex(bin_op.lhs)) |lhs_index| { | 6167 | if (Air.refToIndex(bin_op.lhs)) |lhs_index| { |
| ... | @@ -6221,7 +6221,7 @@ pub const FuncGen = struct { | ... | @@ -6221,7 +6221,7 @@ pub const FuncGen = struct { |
| 6221 | if (isByRef(elem_ty, mod)) { | 6221 | if (isByRef(elem_ty, mod)) { |
| 6222 | if (self.canElideLoad(body_tail)) return ptr; | 6222 | if (self.canElideLoad(body_tail)) return ptr; |
| 6223 | const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); | 6223 | const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)); |
| 6224 | return self.loadByRef(ptr, elem_ty, elem_alignment, false); | 6224 | return self.loadByRef(ptr, elem_ty, elem_alignment, .normal); |
| 6225 | } | 6225 | } |
| 6226 | | 6226 | |
| 6227 | return self.load(ptr, ptr_ty); | 6227 | return self.load(ptr, ptr_ty); |
| ... | @@ -6351,7 +6351,7 @@ pub const FuncGen = struct { | ... | @@ -6351,7 +6351,7 @@ pub const FuncGen = struct { |
| 6351 | | 6351 | |
| 6352 | assert(llvm_field.alignment != 0); | 6352 | assert(llvm_field.alignment != 0); |
| 6353 | const field_alignment = Builder.Alignment.fromByteUnits(llvm_field.alignment); | 6353 | const field_alignment = Builder.Alignment.fromByteUnits(llvm_field.alignment); |
| 6354 | return self.loadByRef(field_ptr, field_ty, field_alignment, false); | 6354 | return self.loadByRef(field_ptr, field_ty, field_alignment, .normal); |
| 6355 | } else { | 6355 | } else { |
| 6356 | return self.load(field_ptr, field_ptr_ty); | 6356 | return self.load(field_ptr, field_ptr_ty); |
| 6357 | } | 6357 | } |
| ... | @@ -6366,7 +6366,7 @@ pub const FuncGen = struct { | ... | @@ -6366,7 +6366,7 @@ pub const FuncGen = struct { |
| 6366 | const payload_alignment = Builder.Alignment.fromByteUnits(layout.payload_align); | 6366 | const payload_alignment = Builder.Alignment.fromByteUnits(layout.payload_align); |
| 6367 | if (isByRef(field_ty, mod)) { | 6367 | if (isByRef(field_ty, mod)) { |
| 6368 | if (canElideLoad(self, body_tail)) return field_ptr; | 6368 | if (canElideLoad(self, body_tail)) return field_ptr; |
| 6369 | return self.loadByRef(field_ptr, field_ty, payload_alignment, false); | 6369 | return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal); |
| 6370 | } else { | 6370 | } else { |
| 6371 | return self.wip.load(.normal, llvm_field_ty, field_ptr, payload_alignment, ""); | 6371 | return self.wip.load(.normal, llvm_field_ty, field_ptr, payload_alignment, ""); |
| 6372 | } | 6372 | } |
| ... | @@ -7150,7 +7150,7 @@ pub const FuncGen = struct { | ... | @@ -7150,7 +7150,7 @@ pub const FuncGen = struct { |
| 7150 | const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); | 7150 | const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, ""); |
| 7151 | if (isByRef(payload_ty, mod)) { | 7151 | if (isByRef(payload_ty, mod)) { |
| 7152 | if (self.canElideLoad(body_tail)) return payload_ptr; | 7152 | if (self.canElideLoad(body_tail)) return payload_ptr; |
| 7153 | return self.loadByRef(payload_ptr, payload_ty, payload_alignment, false); | 7153 | return self.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); |
| 7154 | } | 7154 | } |
| 7155 | const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset]; | 7155 | const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset]; |
| 7156 | return self.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, ""); | 7156 | return self.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, ""); |
| ... | @@ -7346,7 +7346,7 @@ pub const FuncGen = struct { | ... | @@ -7346,7 +7346,7 @@ pub const FuncGen = struct { |
| 7346 | const o = self.dg.object; | 7346 | const o = self.dg.object; |
| 7347 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 7347 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 7348 | const index = pl_op.payload; | 7348 | const index = pl_op.payload; |
| 7349 | return self.wip.callIntrinsic(.@"wasm.memory.size", &.{.i32}, &.{ | 7349 | return self.wip.callIntrinsic(.none, .@"wasm.memory.size", &.{.i32}, &.{ |
| 7350 | try o.builder.intValue(.i32, index), | 7350 | try o.builder.intValue(.i32, index), |
| 7351 | }, ""); | 7351 | }, ""); |
| 7352 | } | 7352 | } |
| ... | @@ -7355,7 +7355,7 @@ pub const FuncGen = struct { | ... | @@ -7355,7 +7355,7 @@ pub const FuncGen = struct { |
| 7355 | const o = self.dg.object; | 7355 | const o = self.dg.object; |
| 7356 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; | 7356 | const pl_op = self.air.instructions.items(.data)[inst].pl_op; |
| 7357 | const index = pl_op.payload; | 7357 | const index = pl_op.payload; |
| 7358 | return self.wip.callIntrinsic(.@"wasm.memory.grow", &.{.i32}, &.{ | 7358 | return self.wip.callIntrinsic(.none, .@"wasm.memory.grow", &.{.i32}, &.{ |
| 7359 | try o.builder.intValue(.i32, index), try self.resolveInst(pl_op.operand), | 7359 | try o.builder.intValue(.i32, index), try self.resolveInst(pl_op.operand), |
| 7360 | }, ""); | 7360 | }, ""); |
| 7361 | } | 7361 | } |
| ... | @@ -7371,13 +7371,11 @@ pub const FuncGen = struct { | ... | @@ -7371,13 +7371,11 @@ pub const FuncGen = struct { |
| 7371 | const index = try self.resolveInst(extra.lhs); | 7371 | const index = try self.resolveInst(extra.lhs); |
| 7372 | const operand = try self.resolveInst(extra.rhs); | 7372 | const operand = try self.resolveInst(extra.rhs); |
| 7373 | | 7373 | |
| 7374 | const kind: Builder.MemoryAccessKind = switch (vector_ptr_ty.isVolatilePtr(mod)) { | 7374 | const access_kind: Builder.MemoryAccessKind = |
| 7375 | false => .normal, | 7375 | if (vector_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; |
| 7376 | true => .@"volatile", | | |
| 7377 | }; | | |
| 7378 | const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod)); | 7376 | const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod)); |
| 7379 | const alignment = Builder.Alignment.fromByteUnits(vector_ptr_ty.ptrAlignment(mod)); | 7377 | const alignment = Builder.Alignment.fromByteUnits(vector_ptr_ty.ptrAlignment(mod)); |
| 7380 | const loaded = try self.wip.load(kind, elem_llvm_ty, vector_ptr, alignment, ""); | 7378 | const loaded = try self.wip.load(access_kind, elem_llvm_ty, vector_ptr, alignment, ""); |
| 7381 | | 7379 | |
| 7382 | const new_vector = try self.wip.insertElement(loaded, operand, index, ""); | 7380 | const new_vector = try self.wip.insertElement(loaded, operand, index, ""); |
| 7383 | _ = try self.store(vector_ptr, vector_ptr_ty, new_vector, .none); | 7381 | _ = try self.store(vector_ptr, vector_ptr_ty, new_vector, .none); |
| ... | @@ -7395,6 +7393,7 @@ pub const FuncGen = struct { | ... | @@ -7395,6 +7393,7 @@ pub const FuncGen = struct { |
| 7395 | | 7393 | |
| 7396 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmin, inst_ty, 2, .{ lhs, rhs }); | 7394 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmin, inst_ty, 2, .{ lhs, rhs }); |
| 7397 | return self.wip.callIntrinsic( | 7395 | return self.wip.callIntrinsic( |
| | 7396 | .none, |
| 7398 | if (scalar_ty.isSignedInt(mod)) .smin else .umin, | 7397 | if (scalar_ty.isSignedInt(mod)) .smin else .umin, |
| 7399 | &.{try o.lowerType(inst_ty)}, | 7398 | &.{try o.lowerType(inst_ty)}, |
| 7400 | &.{ lhs, rhs }, | 7399 | &.{ lhs, rhs }, |
| ... | @@ -7413,6 +7412,7 @@ pub const FuncGen = struct { | ... | @@ -7413,6 +7412,7 @@ pub const FuncGen = struct { |
| 7413 | | 7412 | |
| 7414 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmax, inst_ty, 2, .{ lhs, rhs }); | 7413 | if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmax, inst_ty, 2, .{ lhs, rhs }); |
| 7415 | return self.wip.callIntrinsic( | 7414 | return self.wip.callIntrinsic( |
| | 7415 | .none, |
| 7416 | if (scalar_ty.isSignedInt(mod)) .smax else .umax, | 7416 | if (scalar_ty.isSignedInt(mod)) .smax else .umax, |
| 7417 | &.{try o.lowerType(inst_ty)}, | 7417 | &.{try o.lowerType(inst_ty)}, |
| 7418 | &.{ lhs, rhs }, | 7418 | &.{ lhs, rhs }, |
| ... | @@ -7462,12 +7462,19 @@ pub const FuncGen = struct { | ... | @@ -7462,12 +7462,19 @@ pub const FuncGen = struct { |
| 7462 | | 7462 | |
| 7463 | const intrinsic = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic; | 7463 | const intrinsic = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic; |
| 7464 | const llvm_inst_ty = try o.lowerType(inst_ty); | 7464 | const llvm_inst_ty = try o.lowerType(inst_ty); |
| 7465 | const results = try fg.wip.callIntrinsic(intrinsic, &.{llvm_inst_ty}, &.{ lhs, rhs }, ""); | 7465 | const results = |
| | 7466 | try fg.wip.callIntrinsic(.none, intrinsic, &.{llvm_inst_ty}, &.{ lhs, rhs }, ""); |
| 7466 | | 7467 | |
| 7467 | const overflow_bits = try fg.wip.extractValue(results, &.{1}, ""); | 7468 | const overflow_bits = try fg.wip.extractValue(results, &.{1}, ""); |
| 7468 | const overflow_bits_ty = overflow_bits.typeOfWip(&fg.wip); | 7469 | const overflow_bits_ty = overflow_bits.typeOfWip(&fg.wip); |
| 7469 | const overflow_bit = if (overflow_bits_ty.isVector(&o.builder)) | 7470 | const overflow_bit = if (overflow_bits_ty.isVector(&o.builder)) |
| 7470 | try fg.wip.callIntrinsic(.@"vector.reduce.or", &.{overflow_bits_ty}, &.{overflow_bits}, "") | 7471 | try fg.wip.callIntrinsic( |
| | 7472 | .none, |
| | 7473 | .@"vector.reduce.or", |
| | 7474 | &.{overflow_bits_ty}, |
| | 7475 | &.{overflow_bits}, |
| | 7476 | "", |
| | 7477 | ) |
| 7471 | else | 7478 | else |
| 7472 | overflow_bits; | 7479 | overflow_bits; |
| 7473 | | 7480 | |
| ... | @@ -7501,6 +7508,7 @@ pub const FuncGen = struct { | ... | @@ -7501,6 +7508,7 @@ pub const FuncGen = struct { |
| 7501 | | 7508 | |
| 7502 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{}); | 7509 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{}); |
| 7503 | return self.wip.callIntrinsic( | 7510 | return self.wip.callIntrinsic( |
| | 7511 | .none, |
| 7504 | if (scalar_ty.isSignedInt(mod)) .@"sadd.sat" else .@"uadd.sat", | 7512 | if (scalar_ty.isSignedInt(mod)) .@"sadd.sat" else .@"uadd.sat", |
| 7505 | &.{try o.lowerType(inst_ty)}, | 7513 | &.{try o.lowerType(inst_ty)}, |
| 7506 | &.{ lhs, rhs }, | 7514 | &.{ lhs, rhs }, |
| ... | @@ -7542,6 +7550,7 @@ pub const FuncGen = struct { | ... | @@ -7542,6 +7550,7 @@ pub const FuncGen = struct { |
| 7542 | | 7550 | |
| 7543 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{}); | 7551 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{}); |
| 7544 | return self.wip.callIntrinsic( | 7552 | return self.wip.callIntrinsic( |
| | 7553 | .none, |
| 7545 | if (scalar_ty.isSignedInt(mod)) .@"ssub.sat" else .@"usub.sat", | 7554 | if (scalar_ty.isSignedInt(mod)) .@"ssub.sat" else .@"usub.sat", |
| 7546 | &.{try o.lowerType(inst_ty)}, | 7555 | &.{try o.lowerType(inst_ty)}, |
| 7547 | &.{ lhs, rhs }, | 7556 | &.{ lhs, rhs }, |
| ... | @@ -7583,6 +7592,7 @@ pub const FuncGen = struct { | ... | @@ -7583,6 +7592,7 @@ pub const FuncGen = struct { |
| 7583 | | 7592 | |
| 7584 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{}); | 7593 | if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{}); |
| 7585 | return self.wip.callIntrinsic( | 7594 | return self.wip.callIntrinsic( |
| | 7595 | .none, |
| 7586 | if (scalar_ty.isSignedInt(mod)) .@"smul.fix.sat" else .@"umul.fix.sat", | 7596 | if (scalar_ty.isSignedInt(mod)) .@"smul.fix.sat" else .@"umul.fix.sat", |
| 7587 | &.{try o.lowerType(inst_ty)}, | 7597 | &.{try o.lowerType(inst_ty)}, |
| 7588 | &.{ lhs, rhs, try o.builder.intValue(.i32, 0) }, | 7598 | &.{ lhs, rhs, try o.builder.intValue(.i32, 0) }, |
| ... | @@ -7793,7 +7803,8 @@ pub const FuncGen = struct { | ... | @@ -7793,7 +7803,8 @@ pub const FuncGen = struct { |
| 7793 | const intrinsic = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic; | 7803 | const intrinsic = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic; |
| 7794 | const llvm_inst_ty = try o.lowerType(inst_ty); | 7804 | const llvm_inst_ty = try o.lowerType(inst_ty); |
| 7795 | const llvm_lhs_ty = try o.lowerType(lhs_ty); | 7805 | const llvm_lhs_ty = try o.lowerType(lhs_ty); |
| 7796 | const results = try self.wip.callIntrinsic(intrinsic, &.{llvm_lhs_ty}, &.{ lhs, rhs }, ""); | 7806 | const results = |
| | 7807 | try self.wip.callIntrinsic(.none, intrinsic, &.{llvm_lhs_ty}, &.{ lhs, rhs }, ""); |
| 7797 | | 7808 | |
| 7798 | const result_val = try self.wip.extractValue(results, &.{0}, ""); | 7809 | const result_val = try self.wip.extractValue(results, &.{0}, ""); |
| 7799 | const overflow_bit = try self.wip.extractValue(results, &.{1}, ""); | 7810 | const overflow_bit = try self.wip.extractValue(results, &.{1}, ""); |
| ... | @@ -7998,27 +8009,49 @@ pub const FuncGen = struct { | ... | @@ -7998,27 +8009,49 @@ pub const FuncGen = struct { |
| 7998 | if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) { | 8009 | if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) { |
| 7999 | // Some operations are dedicated LLVM instructions, not available as intrinsics | 8010 | // Some operations are dedicated LLVM instructions, not available as intrinsics |
| 8000 | .neg => return self.wip.un(.fneg, params[0], ""), | 8011 | .neg => return self.wip.un(.fneg, params[0], ""), |
| 8001 | .add => return self.wip.bin(.fadd, params[0], params[1], ""), | 8012 | .add, .sub, .mul, .div, .fmod => return self.wip.bin(switch (op) { |
| 8002 | .sub => return self.wip.bin(.fsub, params[0], params[1], ""), | 8013 | .add => .fadd, |
| 8003 | .mul => return self.wip.bin(.fmul, params[0], params[1], ""), | 8014 | .sub => .fsub, |
| 8004 | .div => return self.wip.bin(.fdiv, params[0], params[1], ""), | 8015 | .mul => .fmul, |
| 8005 | .fmod => return self.wip.bin(.frem, params[0], params[1], ""), | 8016 | .div => .fdiv, |
| 8006 | .fmax => return self.wip.callIntrinsic(.maxnum, &.{llvm_ty}, &params, ""), | 8017 | .fmod => .frem, |
| 8007 | .fmin => return self.wip.callIntrinsic(.minnum, &.{llvm_ty}, &params, ""), | 8018 | else => unreachable, |
| 8008 | .ceil => return self.wip.callIntrinsic(.ceil, &.{llvm_ty}, &params, ""), | 8019 | }, params[0], params[1], ""), |
| 8009 | .cos => return self.wip.callIntrinsic(.cos, &.{llvm_ty}, &params, ""), | 8020 | .fmax, |
| 8010 | .exp => return self.wip.callIntrinsic(.exp, &.{llvm_ty}, &params, ""), | 8021 | .fmin, |
| 8011 | .exp2 => return self.wip.callIntrinsic(.exp2, &.{llvm_ty}, &params, ""), | 8022 | .ceil, |
| 8012 | .fabs => return self.wip.callIntrinsic(.fabs, &.{llvm_ty}, &params, ""), | 8023 | .cos, |
| 8013 | .floor => return self.wip.callIntrinsic(.floor, &.{llvm_ty}, &params, ""), | 8024 | .exp, |
| 8014 | .log => return self.wip.callIntrinsic(.log, &.{llvm_ty}, &params, ""), | 8025 | .exp2, |
| 8015 | .log10 => return self.wip.callIntrinsic(.log10, &.{llvm_ty}, &params, ""), | 8026 | .fabs, |
| 8016 | .log2 => return self.wip.callIntrinsic(.log2, &.{llvm_ty}, &params, ""), | 8027 | .floor, |
| 8017 | .round => return self.wip.callIntrinsic(.round, &.{llvm_ty}, &params, ""), | 8028 | .log, |
| 8018 | .sin => return self.wip.callIntrinsic(.sin, &.{llvm_ty}, &params, ""), | 8029 | .log10, |
| 8019 | .sqrt => return self.wip.callIntrinsic(.sqrt, &.{llvm_ty}, &params, ""), | 8030 | .log2, |
| 8020 | .trunc => return self.wip.callIntrinsic(.trunc, &.{llvm_ty}, &params, ""), | 8031 | .round, |
| 8021 | .fma => return self.wip.callIntrinsic(.fma, &.{llvm_ty}, &params, ""), | 8032 | .sin, |
| | 8033 | .sqrt, |
| | 8034 | .trunc, |
| | 8035 | .fma, |
| | 8036 | => return self.wip.callIntrinsic(.none, switch (op) { |
| | 8037 | .fmax => .maxnum, |
| | 8038 | .fmin => .minnum, |
| | 8039 | .ceil => .ceil, |
| | 8040 | .cos => .cos, |
| | 8041 | .exp => .exp, |
| | 8042 | .exp2 => .exp2, |
| | 8043 | .fabs => .fabs, |
| | 8044 | .floor => .floor, |
| | 8045 | .log => .log, |
| | 8046 | .log10 => .log10, |
| | 8047 | .log2 => .log2, |
| | 8048 | .round => .round, |
| | 8049 | .sin => .sin, |
| | 8050 | .sqrt => .sqrt, |
| | 8051 | .trunc => .trunc, |
| | 8052 | .fma => .fma, |
| | 8053 | else => unreachable, |
| | 8054 | }, &.{llvm_ty}, &params, ""), |
| 8022 | .tan => unreachable, | 8055 | .tan => unreachable, |
| 8023 | }; | 8056 | }; |
| 8024 | | 8057 | |
| ... | @@ -8215,6 +8248,7 @@ pub const FuncGen = struct { | ... | @@ -8215,6 +8248,7 @@ pub const FuncGen = struct { |
| 8215 | const llvm_lhs_ty = try o.lowerType(lhs_ty); | 8248 | const llvm_lhs_ty = try o.lowerType(lhs_ty); |
| 8216 | const llvm_lhs_scalar_ty = llvm_lhs_ty.scalarType(&o.builder); | 8249 | const llvm_lhs_scalar_ty = llvm_lhs_ty.scalarType(&o.builder); |
| 8217 | const result = try self.wip.callIntrinsic( | 8250 | const result = try self.wip.callIntrinsic( |
| | 8251 | .none, |
| 8218 | if (lhs_scalar_ty.isSignedInt(mod)) .@"sshl.sat" else .@"ushl.sat", | 8252 | if (lhs_scalar_ty.isSignedInt(mod)) .@"sshl.sat" else .@"ushl.sat", |
| 8219 | &.{llvm_lhs_ty}, | 8253 | &.{llvm_lhs_ty}, |
| 8220 | &.{ lhs, casted_rhs }, | 8254 | &.{ lhs, casted_rhs }, |
| ... | @@ -8588,21 +8622,14 @@ pub const FuncGen = struct { | ... | @@ -8588,21 +8622,14 @@ pub const FuncGen = struct { |
| 8588 | // Even if safety is disabled, we still emit a memset to undefined since it conveys | 8622 | // Even if safety is disabled, we still emit a memset to undefined since it conveys |
| 8589 | // extra information to LLVM. However, safety makes the difference between using | 8623 | // extra information to LLVM. However, safety makes the difference between using |
| 8590 | // 0xaa or actual undefined for the fill byte. | 8624 | // 0xaa or actual undefined for the fill byte. |
| 8591 | const fill_byte = if (safety) | 8625 | const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(mod)); |
| 8592 | try o.builder.intConst(.i8, 0xaa) | 8626 | _ = try self.wip.callMemSet( |
| 8593 | else | 8627 | dest_ptr, |
| 8594 | try o.builder.undefConst(.i8); | 8628 | Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)), |
| 8595 | const operand_size = operand_ty.abiSize(mod); | 8629 | if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8), |
| 8596 | const usize_ty = try o.lowerType(Type.usize); | 8630 | len, |
| 8597 | const len = try o.builder.intValue(usize_ty, operand_size); | 8631 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal, |
| 8598 | const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); | 8632 | ); |
| 8599 | _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet( | | |
| 8600 | dest_ptr.toLlvm(&self.wip), | | |
| 8601 | fill_byte.toLlvm(&o.builder), | | |
| 8602 | len.toLlvm(&self.wip), | | |
| 8603 | @intCast(dest_ptr_align.toByteUnits() orelse 0), | | |
| 8604 | ptr_ty.isVolatilePtr(mod), | | |
| 8605 | ), &self.wip); | | |
| 8606 | if (safety and mod.comp.bin_file.options.valgrind) { | 8633 | if (safety and mod.comp.bin_file.options.valgrind) { |
| 8607 | try self.valgrindMarkUndef(dest_ptr, len); | 8634 | try self.valgrindMarkUndef(dest_ptr, len); |
| 8608 | } | 8635 | } |
| ... | @@ -8655,14 +8682,14 @@ pub const FuncGen = struct { | ... | @@ -8655,14 +8682,14 @@ pub const FuncGen = struct { |
| 8655 | | 8682 | |
| 8656 | fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | 8683 | fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 8657 | _ = inst; | 8684 | _ = inst; |
| 8658 | _ = try self.wip.callIntrinsic(.trap, &.{}, &.{}, ""); | 8685 | _ = try self.wip.callIntrinsic(.none, .trap, &.{}, &.{}, ""); |
| 8659 | _ = try self.wip.@"unreachable"(); | 8686 | _ = try self.wip.@"unreachable"(); |
| 8660 | return .none; | 8687 | return .none; |
| 8661 | } | 8688 | } |
| 8662 | | 8689 | |
| 8663 | fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | 8690 | fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 8664 | _ = inst; | 8691 | _ = inst; |
| 8665 | _ = try self.wip.callIntrinsic(.debugtrap, &.{}, &.{}, ""); | 8692 | _ = try self.wip.callIntrinsic(.none, .debugtrap, &.{}, &.{}, ""); |
| 8666 | return .none; | 8693 | return .none; |
| 8667 | } | 8694 | } |
| 8668 | | 8695 | |
| ... | @@ -8674,7 +8701,7 @@ pub const FuncGen = struct { | ... | @@ -8674,7 +8701,7 @@ pub const FuncGen = struct { |
| 8674 | // https://github.com/ziglang/zig/issues/11946 | 8701 | // https://github.com/ziglang/zig/issues/11946 |
| 8675 | return o.builder.intValue(llvm_usize, 0); | 8702 | return o.builder.intValue(llvm_usize, 0); |
| 8676 | } | 8703 | } |
| 8677 | const result = try self.wip.callIntrinsic(.returnaddress, &.{}, &.{ | 8704 | const result = try self.wip.callIntrinsic(.none, .returnaddress, &.{}, &.{ |
| 8678 | try o.builder.intValue(.i32, 0), | 8705 | try o.builder.intValue(.i32, 0), |
| 8679 | }, ""); | 8706 | }, ""); |
| 8680 | return self.wip.cast(.ptrtoint, result, llvm_usize, ""); | 8707 | return self.wip.cast(.ptrtoint, result, llvm_usize, ""); |
| ... | @@ -8683,7 +8710,7 @@ pub const FuncGen = struct { | ... | @@ -8683,7 +8710,7 @@ pub const FuncGen = struct { |
| 8683 | fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | 8710 | fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 8684 | _ = inst; | 8711 | _ = inst; |
| 8685 | const o = self.dg.object; | 8712 | const o = self.dg.object; |
| 8686 | const result = try self.wip.callIntrinsic(.frameaddress, &.{.ptr}, &.{ | 8713 | const result = try self.wip.callIntrinsic(.none, .frameaddress, &.{.ptr}, &.{ |
| 8687 | try o.builder.intValue(.i32, 0), | 8714 | try o.builder.intValue(.i32, 0), |
| 8688 | }, ""); | 8715 | }, ""); |
| 8689 | return self.wip.cast(.ptrtoint, result, try o.lowerType(Type.usize), ""); | 8716 | return self.wip.cast(.ptrtoint, result, try o.lowerType(Type.usize), ""); |
| ... | @@ -8835,16 +8862,14 @@ pub const FuncGen = struct { | ... | @@ -8835,16 +8862,14 @@ pub const FuncGen = struct { |
| 8835 | const ptr_alignment = Builder.Alignment.fromByteUnits( | 8862 | const ptr_alignment = Builder.Alignment.fromByteUnits( |
| 8836 | info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod), | 8863 | info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod), |
| 8837 | ); | 8864 | ); |
| 8838 | const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) { | 8865 | const access_kind: Builder.MemoryAccessKind = |
| 8839 | false => .normal, | 8866 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 8840 | true => .@"volatile", | | |
| 8841 | }; | | |
| 8842 | const elem_llvm_ty = try o.lowerType(elem_ty); | 8867 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| 8843 | | 8868 | |
| 8844 | if (llvm_abi_ty != .none) { | 8869 | if (llvm_abi_ty != .none) { |
| 8845 | // operand needs widening and truncating | 8870 | // operand needs widening and truncating |
| 8846 | const loaded = try self.wip.loadAtomic( | 8871 | const loaded = try self.wip.loadAtomic( |
| 8847 | ptr_kind, | 8872 | access_kind, |
| 8848 | llvm_abi_ty, | 8873 | llvm_abi_ty, |
| 8849 | ptr, | 8874 | ptr, |
| 8850 | self.sync_scope, | 8875 | self.sync_scope, |
| ... | @@ -8855,7 +8880,7 @@ pub const FuncGen = struct { | ... | @@ -8855,7 +8880,7 @@ pub const FuncGen = struct { |
| 8855 | return self.wip.cast(.trunc, loaded, elem_llvm_ty, ""); | 8880 | return self.wip.cast(.trunc, loaded, elem_llvm_ty, ""); |
| 8856 | } | 8881 | } |
| 8857 | return self.wip.loadAtomic( | 8882 | return self.wip.loadAtomic( |
| 8858 | ptr_kind, | 8883 | access_kind, |
| 8859 | elem_llvm_ty, | 8884 | elem_llvm_ty, |
| 8860 | ptr, | 8885 | ptr, |
| 8861 | self.sync_scope, | 8886 | self.sync_scope, |
| ... | @@ -8902,7 +8927,8 @@ pub const FuncGen = struct { | ... | @@ -8902,7 +8927,8 @@ pub const FuncGen = struct { |
| 8902 | const elem_ty = self.typeOf(bin_op.rhs); | 8927 | const elem_ty = self.typeOf(bin_op.rhs); |
| 8903 | const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); | 8928 | const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); |
| 8904 | const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty); | 8929 | const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty); |
| 8905 | const is_volatile = ptr_ty.isVolatilePtr(mod); | 8930 | const access_kind: Builder.MemoryAccessKind = |
| | 8931 | if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; |
| 8906 | | 8932 | |
| 8907 | // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless | 8933 | // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless |
| 8908 | // of the length. This means we need to emit a check where we skip the memset when the length | 8934 | // of the length. This means we need to emit a check where we skip the memset when the length |
| ... | @@ -8923,17 +8949,10 @@ pub const FuncGen = struct { | ... | @@ -8923,17 +8949,10 @@ pub const FuncGen = struct { |
| 8923 | try o.builder.undefValue(.i8); | 8949 | try o.builder.undefValue(.i8); |
| 8924 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); | 8950 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8925 | if (intrinsic_len0_traps) { | 8951 | if (intrinsic_len0_traps) { |
| 8926 | try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); | 8952 | try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, access_kind); |
| 8927 | } else { | 8953 | } else { |
| 8928 | _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet( | 8954 | _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind); |
| 8929 | dest_ptr.toLlvm(&self.wip), | | |
| 8930 | fill_byte.toLlvm(&self.wip), | | |
| 8931 | len.toLlvm(&self.wip), | | |
| 8932 | @intCast(dest_ptr_align.toByteUnits() orelse 0), | | |
| 8933 | is_volatile, | | |
| 8934 | ), &self.wip); | | |
| 8935 | } | 8955 | } |
| 8936 | | | |
| 8937 | if (safety and mod.comp.bin_file.options.valgrind) { | 8956 | if (safety and mod.comp.bin_file.options.valgrind) { |
| 8938 | try self.valgrindMarkUndef(dest_ptr, len); | 8957 | try self.valgrindMarkUndef(dest_ptr, len); |
| 8939 | } | 8958 | } |
| ... | @@ -8945,19 +8964,12 @@ pub const FuncGen = struct { | ... | @@ -8945,19 +8964,12 @@ pub const FuncGen = struct { |
| 8945 | // repeating byte pattern of 0 bytes. In such case, the memset | 8964 | // repeating byte pattern of 0 bytes. In such case, the memset |
| 8946 | // intrinsic can be used. | 8965 | // intrinsic can be used. |
| 8947 | if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| { | 8966 | if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| { |
| 8948 | const fill_byte = try self.resolveValue(.{ .ty = Type.u8, .val = byte_val }); | 8967 | const fill_byte = try o.builder.intValue(.i8, byte_val); |
| 8949 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); | 8968 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8950 | | | |
| 8951 | if (intrinsic_len0_traps) { | 8969 | if (intrinsic_len0_traps) { |
| 8952 | try self.safeWasmMemset(dest_ptr, fill_byte.toValue(), len, dest_ptr_align, is_volatile); | 8970 | try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, access_kind); |
| 8953 | } else { | 8971 | } else { |
| 8954 | _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet( | 8972 | _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind); |
| 8955 | dest_ptr.toLlvm(&self.wip), | | |
| 8956 | fill_byte.toLlvm(&o.builder), | | |
| 8957 | len.toLlvm(&self.wip), | | |
| 8958 | @intCast(dest_ptr_align.toByteUnits() orelse 0), | | |
| 8959 | is_volatile, | | |
| 8960 | ), &self.wip); | | |
| 8961 | } | 8973 | } |
| 8962 | return .none; | 8974 | return .none; |
| 8963 | } | 8975 | } |
| ... | @@ -8972,15 +8984,9 @@ pub const FuncGen = struct { | ... | @@ -8972,15 +8984,9 @@ pub const FuncGen = struct { |
| 8972 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); | 8984 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 8973 | | 8985 | |
| 8974 | if (intrinsic_len0_traps) { | 8986 | if (intrinsic_len0_traps) { |
| 8975 | try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); | 8987 | try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, access_kind); |
| 8976 | } else { | 8988 | } else { |
| 8977 | _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet( | 8989 | _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind); |
| 8978 | dest_ptr.toLlvm(&self.wip), | | |
| 8979 | fill_byte.toLlvm(&self.wip), | | |
| 8980 | len.toLlvm(&self.wip), | | |
| 8981 | @intCast(dest_ptr_align.toByteUnits() orelse 0), | | |
| 8982 | is_volatile, | | |
| 8983 | ), &self.wip); | | |
| 8984 | } | 8990 | } |
| 8985 | return .none; | 8991 | return .none; |
| 8986 | } | 8992 | } |
| ... | @@ -9006,10 +9012,10 @@ pub const FuncGen = struct { | ... | @@ -9006,10 +9012,10 @@ pub const FuncGen = struct { |
| 9006 | const body_block = try self.wip.block(1, "InlineMemsetBody"); | 9012 | const body_block = try self.wip.block(1, "InlineMemsetBody"); |
| 9007 | const end_block = try self.wip.block(1, "InlineMemsetEnd"); | 9013 | const end_block = try self.wip.block(1, "InlineMemsetEnd"); |
| 9008 | | 9014 | |
| 9009 | const usize_ty = try o.lowerType(Type.usize); | 9015 | const llvm_usize_ty = try o.lowerType(Type.usize); |
| 9010 | const len = switch (ptr_ty.ptrSize(mod)) { | 9016 | const len = switch (ptr_ty.ptrSize(mod)) { |
| 9011 | .Slice => try self.wip.extractValue(dest_slice, &.{1}, ""), | 9017 | .Slice => try self.wip.extractValue(dest_slice, &.{1}, ""), |
| 9012 | .One => try o.builder.intValue(usize_ty, ptr_ty.childType(mod).arrayLen(mod)), | 9018 | .One => try o.builder.intValue(llvm_usize_ty, ptr_ty.childType(mod).arrayLen(mod)), |
| 9013 | .Many, .C => unreachable, | 9019 | .Many, .C => unreachable, |
| 9014 | }; | 9020 | }; |
| 9015 | const elem_llvm_ty = try o.lowerType(elem_ty); | 9021 | const elem_llvm_ty = try o.lowerType(elem_ty); |
| ... | @@ -9022,25 +9028,22 @@ pub const FuncGen = struct { | ... | @@ -9022,25 +9028,22 @@ pub const FuncGen = struct { |
| 9022 | _ = try self.wip.brCond(end, body_block, end_block); | 9028 | _ = try self.wip.brCond(end, body_block, end_block); |
| 9023 | | 9029 | |
| 9024 | self.wip.cursor = .{ .block = body_block }; | 9030 | self.wip.cursor = .{ .block = body_block }; |
| 9025 | const elem_abi_alignment = elem_ty.abiAlignment(mod); | 9031 | const elem_abi_align = elem_ty.abiAlignment(mod); |
| 9026 | const it_ptr_alignment = Builder.Alignment.fromByteUnits( | 9032 | const it_ptr_align = Builder.Alignment.fromByteUnits( |
| 9027 | @min(elem_abi_alignment, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)), | 9033 | @min(elem_abi_align, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)), |
| 9028 | ); | 9034 | ); |
| 9029 | if (isByRef(elem_ty, mod)) { | 9035 | if (isByRef(elem_ty, mod)) { |
| 9030 | _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy( | 9036 | _ = try self.wip.callMemCpy( |
| 9031 | it_ptr.toValue().toLlvm(&self.wip), | 9037 | it_ptr.toValue(), |
| 9032 | @intCast(it_ptr_alignment.toByteUnits() orelse 0), | 9038 | it_ptr_align, |
| 9033 | value.toLlvm(&self.wip), | 9039 | value, |
| 9034 | elem_abi_alignment, | 9040 | Builder.Alignment.fromByteUnits(elem_abi_align), |
| 9035 | (try o.builder.intConst(usize_ty, elem_abi_size)).toLlvm(&o.builder), | 9041 | try o.builder.intValue(llvm_usize_ty, elem_abi_size), |
| 9036 | is_volatile, | 9042 | access_kind, |
| 9037 | ), &self.wip); | 9043 | ); |
| 9038 | } else _ = try self.wip.store(switch (is_volatile) { | 9044 | } else _ = try self.wip.store(access_kind, value, it_ptr.toValue(), it_ptr_align); |
| 9039 | false => .normal, | | |
| 9040 | true => .@"volatile", | | |
| 9041 | }, value, it_ptr.toValue(), it_ptr_alignment); | | |
| 9042 | const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{ | 9045 | const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{ |
| 9043 | try o.builder.intValue(usize_ty, 1), | 9046 | try o.builder.intValue(llvm_usize_ty, 1), |
| 9044 | }, ""); | 9047 | }, ""); |
| 9045 | _ = try self.wip.br(loop_block); | 9048 | _ = try self.wip.br(loop_block); |
| 9046 | | 9049 | |
| ... | @@ -9055,7 +9058,7 @@ pub const FuncGen = struct { | ... | @@ -9055,7 +9058,7 @@ pub const FuncGen = struct { |
| 9055 | fill_byte: Builder.Value, | 9058 | fill_byte: Builder.Value, |
| 9056 | len: Builder.Value, | 9059 | len: Builder.Value, |
| 9057 | dest_ptr_align: Builder.Alignment, | 9060 | dest_ptr_align: Builder.Alignment, |
| 9058 | is_volatile: bool, | 9061 | access_kind: Builder.MemoryAccessKind, |
| 9059 | ) !void { | 9062 | ) !void { |
| 9060 | const o = self.dg.object; | 9063 | const o = self.dg.object; |
| 9061 | const llvm_usize_ty = try o.lowerType(Type.usize); | 9064 | const llvm_usize_ty = try o.lowerType(Type.usize); |
| ... | @@ -9064,13 +9067,7 @@ pub const FuncGen = struct { | ... | @@ -9064,13 +9067,7 @@ pub const FuncGen = struct { |
| 9064 | const end_block = try self.wip.block(2, "MemsetTrapEnd"); | 9067 | const end_block = try self.wip.block(2, "MemsetTrapEnd"); |
| 9065 | _ = try self.wip.brCond(cond, memset_block, end_block); | 9068 | _ = try self.wip.brCond(cond, memset_block, end_block); |
| 9066 | self.wip.cursor = .{ .block = memset_block }; | 9069 | self.wip.cursor = .{ .block = memset_block }; |
| 9067 | _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet( | 9070 | _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind); |
| 9068 | dest_ptr.toLlvm(&self.wip), | | |
| 9069 | fill_byte.toLlvm(&self.wip), | | |
| 9070 | len.toLlvm(&self.wip), | | |
| 9071 | @intCast(dest_ptr_align.toByteUnits() orelse 0), | | |
| 9072 | is_volatile, | | |
| 9073 | ), &self.wip); | | |
| 9074 | _ = try self.wip.br(end_block); | 9071 | _ = try self.wip.br(end_block); |
| 9075 | self.wip.cursor = .{ .block = end_block }; | 9072 | self.wip.cursor = .{ .block = end_block }; |
| 9076 | } | 9073 | } |
| ... | @@ -9086,7 +9083,8 @@ pub const FuncGen = struct { | ... | @@ -9086,7 +9083,8 @@ pub const FuncGen = struct { |
| 9086 | const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ptr_ty); | 9083 | const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ptr_ty); |
| 9087 | const len = try self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty); | 9084 | const len = try self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty); |
| 9088 | const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ptr_ty); | 9085 | const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ptr_ty); |
| 9089 | const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod); | 9086 | const access_kind: Builder.MemoryAccessKind = if (src_ptr_ty.isVolatilePtr(mod) or |
| | 9087 | dest_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal; |
| 9090 | | 9088 | |
| 9091 | // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction. | 9089 | // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction. |
| 9092 | // This instruction will trap on an invalid address, regardless of the length. | 9090 | // This instruction will trap on an invalid address, regardless of the length. |
| ... | @@ -9103,27 +9101,27 @@ pub const FuncGen = struct { | ... | @@ -9103,27 +9101,27 @@ pub const FuncGen = struct { |
| 9103 | const end_block = try self.wip.block(2, "MemcpyTrapEnd"); | 9101 | const end_block = try self.wip.block(2, "MemcpyTrapEnd"); |
| 9104 | _ = try self.wip.brCond(cond, memcpy_block, end_block); | 9102 | _ = try self.wip.brCond(cond, memcpy_block, end_block); |
| 9105 | self.wip.cursor = .{ .block = memcpy_block }; | 9103 | self.wip.cursor = .{ .block = memcpy_block }; |
| 9106 | _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy( | 9104 | _ = try self.wip.callMemCpy( |
| 9107 | dest_ptr.toLlvm(&self.wip), | 9105 | dest_ptr, |
| 9108 | dest_ptr_ty.ptrAlignment(mod), | 9106 | Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)), |
| 9109 | src_ptr.toLlvm(&self.wip), | 9107 | src_ptr, |
| 9110 | src_ptr_ty.ptrAlignment(mod), | 9108 | Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)), |
| 9111 | len.toLlvm(&self.wip), | 9109 | len, |
| 9112 | is_volatile, | 9110 | access_kind, |
| 9113 | ), &self.wip); | 9111 | ); |
| 9114 | _ = try self.wip.br(end_block); | 9112 | _ = try self.wip.br(end_block); |
| 9115 | self.wip.cursor = .{ .block = end_block }; | 9113 | self.wip.cursor = .{ .block = end_block }; |
| 9116 | return .none; | 9114 | return .none; |
| 9117 | } | 9115 | } |
| 9118 | | 9116 | |
| 9119 | _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy( | 9117 | _ = try self.wip.callMemCpy( |
| 9120 | dest_ptr.toLlvm(&self.wip), | 9118 | dest_ptr, |
| 9121 | dest_ptr_ty.ptrAlignment(mod), | 9119 | Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)), |
| 9122 | src_ptr.toLlvm(&self.wip), | 9120 | src_ptr, |
| 9123 | src_ptr_ty.ptrAlignment(mod), | 9121 | Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)), |
| 9124 | len.toLlvm(&self.wip), | 9122 | len, |
| 9125 | is_volatile, | 9123 | access_kind, |
| 9126 | ), &self.wip); | 9124 | ); |
| 9127 | return .none; | 9125 | return .none; |
| 9128 | } | 9126 | } |
| 9129 | | 9127 | |
| ... | @@ -9196,8 +9194,8 @@ pub const FuncGen = struct { | ... | @@ -9196,8 +9194,8 @@ pub const FuncGen = struct { |
| 9196 | const operand_ty = self.typeOf(ty_op.operand); | 9194 | const operand_ty = self.typeOf(ty_op.operand); |
| 9197 | const operand = try self.resolveInst(ty_op.operand); | 9195 | const operand = try self.resolveInst(ty_op.operand); |
| 9198 | | 9196 | |
| 9199 | const result = | 9197 | const result = try self.wip.callIntrinsic( |
| 9200 | try self.wip.callIntrinsic( | 9198 | .none, |
| 9201 | intrinsic, | 9199 | intrinsic, |
| 9202 | &.{try o.lowerType(operand_ty)}, | 9200 | &.{try o.lowerType(operand_ty)}, |
| 9203 | &.{ operand, .false }, | 9201 | &.{ operand, .false }, |
| ... | @@ -9214,6 +9212,7 @@ pub const FuncGen = struct { | ... | @@ -9214,6 +9212,7 @@ pub const FuncGen = struct { |
| 9214 | const operand = try self.resolveInst(ty_op.operand); | 9212 | const operand = try self.resolveInst(ty_op.operand); |
| 9215 | | 9213 | |
| 9216 | const result = try self.wip.callIntrinsic( | 9214 | const result = try self.wip.callIntrinsic( |
| | 9215 | .none, |
| 9217 | intrinsic, | 9216 | intrinsic, |
| 9218 | &.{try o.lowerType(operand_ty)}, | 9217 | &.{try o.lowerType(operand_ty)}, |
| 9219 | &.{operand}, | 9218 | &.{operand}, |
| ... | @@ -9251,7 +9250,7 @@ pub const FuncGen = struct { | ... | @@ -9251,7 +9250,7 @@ pub const FuncGen = struct { |
| 9251 | bits = bits + 8; | 9250 | bits = bits + 8; |
| 9252 | } | 9251 | } |
| 9253 | | 9252 | |
| 9254 | const result = try self.wip.callIntrinsic(.bswap, &.{llvm_operand_ty}, &.{operand}, ""); | 9253 | const result = try self.wip.callIntrinsic(.none, .bswap, &.{llvm_operand_ty}, &.{operand}, ""); |
| 9255 | return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty), ""); | 9254 | return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty), ""); |
| 9256 | } | 9255 | } |
| 9257 | | 9256 | |
| ... | @@ -9646,14 +9645,14 @@ pub const FuncGen = struct { | ... | @@ -9646,14 +9645,14 @@ pub const FuncGen = struct { |
| 9646 | const llvm_scalar_ty = try o.lowerType(scalar_ty); | 9645 | const llvm_scalar_ty = try o.lowerType(scalar_ty); |
| 9647 | | 9646 | |
| 9648 | switch (reduce.operation) { | 9647 | switch (reduce.operation) { |
| 9649 | .And, .Or, .Xor => return self.wip.callIntrinsic(switch (reduce.operation) { | 9648 | .And, .Or, .Xor => return self.wip.callIntrinsic(.none, switch (reduce.operation) { |
| 9650 | .And => .@"vector.reduce.and", | 9649 | .And => .@"vector.reduce.and", |
| 9651 | .Or => .@"vector.reduce.or", | 9650 | .Or => .@"vector.reduce.or", |
| 9652 | .Xor => .@"vector.reduce.xor", | 9651 | .Xor => .@"vector.reduce.xor", |
| 9653 | else => unreachable, | 9652 | else => unreachable, |
| 9654 | }, &.{llvm_operand_ty}, &.{operand}, ""), | 9653 | }, &.{llvm_operand_ty}, &.{operand}, ""), |
| 9655 | .Min, .Max => switch (scalar_ty.zigTypeTag(mod)) { | 9654 | .Min, .Max => switch (scalar_ty.zigTypeTag(mod)) { |
| 9656 | .Int => return self.wip.callIntrinsic(switch (reduce.operation) { | 9655 | .Int => return self.wip.callIntrinsic(.none, switch (reduce.operation) { |
| 9657 | .Min => if (scalar_ty.isSignedInt(mod)) | 9656 | .Min => if (scalar_ty.isSignedInt(mod)) |
| 9658 | .@"vector.reduce.smin" | 9657 | .@"vector.reduce.smin" |
| 9659 | else | 9658 | else |
| ... | @@ -9665,7 +9664,7 @@ pub const FuncGen = struct { | ... | @@ -9665,7 +9664,7 @@ pub const FuncGen = struct { |
| 9665 | else => unreachable, | 9664 | else => unreachable, |
| 9666 | }, &.{llvm_operand_ty}, &.{operand}, ""), | 9665 | }, &.{llvm_operand_ty}, &.{operand}, ""), |
| 9667 | .Float => if (intrinsicsAllowed(scalar_ty, target)) | 9666 | .Float => if (intrinsicsAllowed(scalar_ty, target)) |
| 9668 | return self.wip.callIntrinsic(switch (reduce.operation) { | 9667 | return self.wip.callIntrinsic(.none, switch (reduce.operation) { |
| 9669 | .Min => .@"vector.reduce.fmin", | 9668 | .Min => .@"vector.reduce.fmin", |
| 9670 | .Max => .@"vector.reduce.fmax", | 9669 | .Max => .@"vector.reduce.fmax", |
| 9671 | else => unreachable, | 9670 | else => unreachable, |
| ... | @@ -9673,13 +9672,13 @@ pub const FuncGen = struct { | ... | @@ -9673,13 +9672,13 @@ pub const FuncGen = struct { |
| 9673 | else => unreachable, | 9672 | else => unreachable, |
| 9674 | }, | 9673 | }, |
| 9675 | .Add, .Mul => switch (scalar_ty.zigTypeTag(mod)) { | 9674 | .Add, .Mul => switch (scalar_ty.zigTypeTag(mod)) { |
| 9676 | .Int => return self.wip.callIntrinsic(switch (reduce.operation) { | 9675 | .Int => return self.wip.callIntrinsic(.none, switch (reduce.operation) { |
| 9677 | .Add => .@"vector.reduce.add", | 9676 | .Add => .@"vector.reduce.add", |
| 9678 | .Mul => .@"vector.reduce.mul", | 9677 | .Mul => .@"vector.reduce.mul", |
| 9679 | else => unreachable, | 9678 | else => unreachable, |
| 9680 | }, &.{llvm_operand_ty}, &.{operand}, ""), | 9679 | }, &.{llvm_operand_ty}, &.{operand}, ""), |
| 9681 | .Float => if (intrinsicsAllowed(scalar_ty, target)) | 9680 | .Float => if (intrinsicsAllowed(scalar_ty, target)) |
| 9682 | return self.wip.callIntrinsic(switch (reduce.operation) { | 9681 | return self.wip.callIntrinsic(.none, switch (reduce.operation) { |
| 9683 | .Add => .@"vector.reduce.fadd", | 9682 | .Add => .@"vector.reduce.fadd", |
| 9684 | .Mul => .@"vector.reduce.fmul", | 9683 | .Mul => .@"vector.reduce.fmul", |
| 9685 | else => unreachable, | 9684 | else => unreachable, |
| ... | @@ -10032,7 +10031,7 @@ pub const FuncGen = struct { | ... | @@ -10032,7 +10031,7 @@ pub const FuncGen = struct { |
| 10032 | .data => {}, | 10031 | .data => {}, |
| 10033 | } | 10032 | } |
| 10034 | | 10033 | |
| 10035 | _ = try self.wip.callIntrinsic(.prefetch, &.{.ptr}, &.{ | 10034 | _ = try self.wip.callIntrinsic(.none, .prefetch, &.{.ptr}, &.{ |
| 10036 | try self.resolveInst(prefetch.ptr), | 10035 | try self.resolveInst(prefetch.ptr), |
| 10037 | try o.builder.intValue(.i32, prefetch.rw), | 10036 | try o.builder.intValue(.i32, prefetch.rw), |
| 10038 | try o.builder.intValue(.i32, prefetch.locality), | 10037 | try o.builder.intValue(.i32, prefetch.locality), |
| ... | @@ -10056,14 +10055,12 @@ pub const FuncGen = struct { | ... | @@ -10056,14 +10055,12 @@ pub const FuncGen = struct { |
| 10056 | default: u32, | 10055 | default: u32, |
| 10057 | comptime basename: []const u8, | 10056 | comptime basename: []const u8, |
| 10058 | ) !Builder.Value { | 10057 | ) !Builder.Value { |
| 10059 | const o = self.dg.object; | 10058 | return self.wip.callIntrinsic(.none, switch (dimension) { |
| 10060 | const intrinsic = switch (dimension) { | | |
| 10061 | 0 => @field(Builder.Intrinsic, basename ++ ".x"), | 10059 | 0 => @field(Builder.Intrinsic, basename ++ ".x"), |
| 10062 | 1 => @field(Builder.Intrinsic, basename ++ ".y"), | 10060 | 1 => @field(Builder.Intrinsic, basename ++ ".y"), |
| 10063 | 2 => @field(Builder.Intrinsic, basename ++ ".z"), | 10061 | 2 => @field(Builder.Intrinsic, basename ++ ".z"), |
| 10064 | else => return o.builder.intValue(.i32, default), | 10062 | else => return self.dg.object.builder.intValue(.i32, default), |
| 10065 | }; | 10063 | }, &.{}, &.{}, ""); |
| 10066 | return self.wip.callIntrinsic(intrinsic, &.{}, &.{}, ""); | | |
| 10067 | } | 10064 | } |
| 10068 | | 10065 | |
| 10069 | fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { | 10066 | fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| ... | @@ -10087,7 +10084,7 @@ pub const FuncGen = struct { | ... | @@ -10087,7 +10084,7 @@ pub const FuncGen = struct { |
| 10087 | | 10084 | |
| 10088 | // Fetch the dispatch pointer, which points to this structure: | 10085 | // Fetch the dispatch pointer, which points to this structure: |
| 10089 | // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913 | 10086 | // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913 |
| 10090 | const dispatch_ptr = try self.wip.callIntrinsic(.@"amdgcn.dispatch.ptr", &.{}, &.{}, ""); | 10087 | const dispatch_ptr = try self.wip.callIntrinsic(.none, .@"amdgcn.dispatch.ptr", &.{}, &.{}, ""); |
| 10091 | | 10088 | |
| 10092 | // Load the work_group_* member from the struct as u16. | 10089 | // Load the work_group_* member from the struct as u16. |
| 10093 | // Just treat the dispatch pointer as an array of u16 to keep things simple. | 10090 | // Just treat the dispatch pointer as an array of u16 to keep things simple. |
| ... | @@ -10188,7 +10185,7 @@ pub const FuncGen = struct { | ... | @@ -10188,7 +10185,7 @@ pub const FuncGen = struct { |
| 10188 | if (can_elide_load) | 10185 | if (can_elide_load) |
| 10189 | return payload_ptr; | 10186 | return payload_ptr; |
| 10190 | | 10187 | |
| 10191 | return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false); | 10188 | return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal); |
| 10192 | } | 10189 | } |
| 10193 | const payload_llvm_ty = try o.lowerType(payload_ty); | 10190 | const payload_llvm_ty = try o.lowerType(payload_ty); |
| 10194 | return fg.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, ""); | 10191 | return fg.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, ""); |
| ... | @@ -10297,7 +10294,7 @@ pub const FuncGen = struct { | ... | @@ -10297,7 +10294,7 @@ pub const FuncGen = struct { |
| 10297 | ptr: Builder.Value, | 10294 | ptr: Builder.Value, |
| 10298 | pointee_type: Type, | 10295 | pointee_type: Type, |
| 10299 | ptr_alignment: Builder.Alignment, | 10296 | ptr_alignment: Builder.Alignment, |
| 10300 | is_volatile: bool, | 10297 | access_kind: Builder.MemoryAccessKind, |
| 10301 | ) !Builder.Value { | 10298 | ) !Builder.Value { |
| 10302 | const o = fg.dg.object; | 10299 | const o = fg.dg.object; |
| 10303 | const mod = o.module; | 10300 | const mod = o.module; |
| ... | @@ -10306,16 +10303,15 @@ pub const FuncGen = struct { | ... | @@ -10306,16 +10303,15 @@ pub const FuncGen = struct { |
| 10306 | @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)), | 10303 | @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)), |
| 10307 | ); | 10304 | ); |
| 10308 | const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align); | 10305 | const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align); |
| 10309 | const usize_ty = try o.lowerType(Type.usize); | | |
| 10310 | const size_bytes = pointee_type.abiSize(mod); | 10306 | const size_bytes = pointee_type.abiSize(mod); |
| 10311 | _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildMemCpy( | 10307 | _ = try fg.wip.callMemCpy( |
| 10312 | result_ptr.toLlvm(&fg.wip), | 10308 | result_ptr, |
| 10313 | @intCast(result_align.toByteUnits() orelse 0), | 10309 | result_align, |
| 10314 | ptr.toLlvm(&fg.wip), | 10310 | ptr, |
| 10315 | @intCast(ptr_alignment.toByteUnits() orelse 0), | 10311 | ptr_alignment, |
| 10316 | (try o.builder.intConst(usize_ty, size_bytes)).toLlvm(&o.builder), | 10312 | try o.builder.intValue(try o.lowerType(Type.usize), size_bytes), |
| 10317 | is_volatile, | 10313 | access_kind, |
| 10318 | ), &fg.wip); | 10314 | ); |
| 10319 | return result_ptr; | 10315 | return result_ptr; |
| 10320 | } | 10316 | } |
| 10321 | | 10317 | |
| ... | @@ -10332,10 +10328,8 @@ pub const FuncGen = struct { | ... | @@ -10332,10 +10328,8 @@ pub const FuncGen = struct { |
| 10332 | const ptr_alignment = Builder.Alignment.fromByteUnits( | 10328 | const ptr_alignment = Builder.Alignment.fromByteUnits( |
| 10333 | info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod), | 10329 | info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod), |
| 10334 | ); | 10330 | ); |
| 10335 | const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) { | 10331 | const access_kind: Builder.MemoryAccessKind = |
| 10336 | false => .normal, | 10332 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 10337 | true => .@"volatile", | | |
| 10338 | }; | | |
| 10339 | | 10333 | |
| 10340 | assert(info.flags.vector_index != .runtime); | 10334 | assert(info.flags.vector_index != .runtime); |
| 10341 | if (info.flags.vector_index != .none) { | 10335 | if (info.flags.vector_index != .none) { |
| ... | @@ -10343,19 +10337,20 @@ pub const FuncGen = struct { | ... | @@ -10343,19 +10337,20 @@ pub const FuncGen = struct { |
| 10343 | const vec_elem_ty = try o.lowerType(elem_ty); | 10337 | const vec_elem_ty = try o.lowerType(elem_ty); |
| 10344 | const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty); | 10338 | const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty); |
| 10345 | | 10339 | |
| 10346 | const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, ""); | 10340 | const loaded_vector = try self.wip.load(access_kind, vec_ty, ptr, ptr_alignment, ""); |
| 10347 | return self.wip.extractElement(loaded_vector, index_u32, ""); | 10341 | return self.wip.extractElement(loaded_vector, index_u32, ""); |
| 10348 | } | 10342 | } |
| 10349 | | 10343 | |
| 10350 | if (info.packed_offset.host_size == 0) { | 10344 | if (info.packed_offset.host_size == 0) { |
| 10351 | if (isByRef(elem_ty, mod)) { | 10345 | if (isByRef(elem_ty, mod)) { |
| 10352 | return self.loadByRef(ptr, elem_ty, ptr_alignment, info.flags.is_volatile); | 10346 | return self.loadByRef(ptr, elem_ty, ptr_alignment, access_kind); |
| 10353 | } | 10347 | } |
| 10354 | return self.wip.load(ptr_kind, try o.lowerType(elem_ty), ptr, ptr_alignment, ""); | 10348 | return self.wip.load(access_kind, try o.lowerType(elem_ty), ptr, ptr_alignment, ""); |
| 10355 | } | 10349 | } |
| 10356 | | 10350 | |
| 10357 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); | 10351 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); |
| 10358 | const containing_int = try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, ""); | 10352 | const containing_int = |
| | 10353 | try self.wip.load(access_kind, containing_int_ty, ptr, ptr_alignment, ""); |
| 10359 | | 10354 | |
| 10360 | const elem_bits = ptr_ty.childType(mod).bitSize(mod); | 10355 | const elem_bits = ptr_ty.childType(mod).bitSize(mod); |
| 10361 | const shift_amt = try o.builder.intValue(containing_int_ty, info.packed_offset.bit_offset); | 10356 | const shift_amt = try o.builder.intValue(containing_int_ty, info.packed_offset.bit_offset); |
| ... | @@ -10402,10 +10397,8 @@ pub const FuncGen = struct { | ... | @@ -10402,10 +10397,8 @@ pub const FuncGen = struct { |
| 10402 | return; | 10397 | return; |
| 10403 | } | 10398 | } |
| 10404 | const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); | 10399 | const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)); |
| 10405 | const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) { | 10400 | const access_kind: Builder.MemoryAccessKind = |
| 10406 | false => .normal, | 10401 | if (info.flags.is_volatile) .@"volatile" else .normal; |
| 10407 | true => .@"volatile", | | |
| 10408 | }; | | |
| 10409 | | 10402 | |
| 10410 | assert(info.flags.vector_index != .runtime); | 10403 | assert(info.flags.vector_index != .runtime); |
| 10411 | if (info.flags.vector_index != .none) { | 10404 | if (info.flags.vector_index != .none) { |
| ... | @@ -10413,12 +10406,12 @@ pub const FuncGen = struct { | ... | @@ -10413,12 +10406,12 @@ pub const FuncGen = struct { |
| 10413 | const vec_elem_ty = try o.lowerType(elem_ty); | 10406 | const vec_elem_ty = try o.lowerType(elem_ty); |
| 10414 | const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty); | 10407 | const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty); |
| 10415 | | 10408 | |
| 10416 | const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, ""); | 10409 | const loaded_vector = try self.wip.load(access_kind, vec_ty, ptr, ptr_alignment, ""); |
| 10417 | | 10410 | |
| 10418 | const modified_vector = try self.wip.insertElement(loaded_vector, elem, index_u32, ""); | 10411 | const modified_vector = try self.wip.insertElement(loaded_vector, elem, index_u32, ""); |
| 10419 | | 10412 | |
| 10420 | assert(ordering == .none); | 10413 | assert(ordering == .none); |
| 10421 | _ = try self.wip.store(ptr_kind, modified_vector, ptr, ptr_alignment); | 10414 | _ = try self.wip.store(access_kind, modified_vector, ptr, ptr_alignment); |
| 10422 | return; | 10415 | return; |
| 10423 | } | 10416 | } |
| 10424 | | 10417 | |
| ... | @@ -10426,7 +10419,7 @@ pub const FuncGen = struct { | ... | @@ -10426,7 +10419,7 @@ pub const FuncGen = struct { |
| 10426 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); | 10419 | const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8)); |
| 10427 | assert(ordering == .none); | 10420 | assert(ordering == .none); |
| 10428 | const containing_int = | 10421 | const containing_int = |
| 10429 | try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, ""); | 10422 | try self.wip.load(access_kind, containing_int_ty, ptr, ptr_alignment, ""); |
| 10430 | const elem_bits = ptr_ty.childType(mod).bitSize(mod); | 10423 | const elem_bits = ptr_ty.childType(mod).bitSize(mod); |
| 10431 | const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset); | 10424 | const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset); |
| 10432 | // Convert to equally-sized integer type in order to perform the bit | 10425 | // Convert to equally-sized integer type in order to perform the bit |
| ... | @@ -10450,23 +10443,29 @@ pub const FuncGen = struct { | ... | @@ -10450,23 +10443,29 @@ pub const FuncGen = struct { |
| 10450 | const ored_value = try self.wip.bin(.@"or", shifted_value, anded_containing_int, ""); | 10443 | const ored_value = try self.wip.bin(.@"or", shifted_value, anded_containing_int, ""); |
| 10451 | | 10444 | |
| 10452 | assert(ordering == .none); | 10445 | assert(ordering == .none); |
| 10453 | _ = try self.wip.store(ptr_kind, ored_value, ptr, ptr_alignment); | 10446 | _ = try self.wip.store(access_kind, ored_value, ptr, ptr_alignment); |
| 10454 | return; | 10447 | return; |
| 10455 | } | 10448 | } |
| 10456 | if (!isByRef(elem_ty, mod)) { | 10449 | if (!isByRef(elem_ty, mod)) { |
| 10457 | _ = try self.wip.storeAtomic(ptr_kind, elem, ptr, self.sync_scope, ordering, ptr_alignment); | 10450 | _ = try self.wip.storeAtomic( |
| | 10451 | access_kind, |
| | 10452 | elem, |
| | 10453 | ptr, |
| | 10454 | self.sync_scope, |
| | 10455 | ordering, |
| | 10456 | ptr_alignment, |
| | 10457 | ); |
| 10458 | return; | 10458 | return; |
| 10459 | } | 10459 | } |
| 10460 | assert(ordering == .none); | 10460 | assert(ordering == .none); |
| 10461 | const size_bytes = elem_ty.abiSize(mod); | 10461 | _ = try self.wip.callMemCpy( |
| 10462 | _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy( | 10462 | ptr, |
| 10463 | ptr.toLlvm(&self.wip), | 10463 | ptr_alignment, |
| 10464 | @intCast(ptr_alignment.toByteUnits() orelse 0), | 10464 | elem, |
| 10465 | elem.toLlvm(&self.wip), | 10465 | Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)), |
| 10466 | elem_ty.abiAlignment(mod), | 10466 | try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(mod)), |
| 10467 | (try o.builder.intConst(try o.lowerType(Type.usize), size_bytes)).toLlvm(&o.builder), | 10467 | access_kind, |
| 10468 | info.flags.is_volatile, | 10468 | ); |
| 10469 | ), &self.wip); | | |
| 10470 | } | 10469 | } |
| 10471 | | 10470 | |
| 10472 | fn valgrindMarkUndef(fg: *FuncGen, ptr: Builder.Value, len: Builder.Value) Allocator.Error!void { | 10471 | fn valgrindMarkUndef(fg: *FuncGen, ptr: Builder.Value, len: Builder.Value) Allocator.Error!void { |