aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-09-24 17:33:06 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-09-24 17:33:06 -0700
commit42aa1ea115eca3dcc704eddf020ce87271a41174 (patch)
tree3242b53425c599af929446e6776a2f6b3a0c6966 /src/codegen
parent87fd502fb68f8f488e6eba6b1f7d70902d6bfe5a (diff)
downloadzig-42aa1ea115eca3dcc704eddf020ce87271a41174.tar.gz
zig-42aa1ea115eca3dcc704eddf020ce87271a41174.zip
stage2: implement `@memset` and `@memcpy` builtins
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig46
-rw-r--r--src/codegen/llvm.zig53
-rw-r--r--src/codegen/llvm/bindings.zig19
3 files changed, 117 insertions, 1 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index a82f0e57f7..16b13db292 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -953,6 +953,8 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
.cmpxchg_strong => try airCmpxchg(f, inst, "strong"),
.atomic_rmw => try airAtomicRmw(f, inst),
.atomic_load => try airAtomicLoad(f, inst),
+ .memset => try airMemset(f, inst),
+ .memcpy => try airMemcpy(f, inst),
.int_to_float,
.float_to_int,
@@ -2005,8 +2007,12 @@ fn airAtomicRmw(f: *Function, inst: Air.Inst.Index) !CValue {
fn airAtomicLoad(f: *Function, inst: Air.Inst.Index) !CValue {
const atomic_load = f.air.instructions.items(.data)[inst].atomic_load;
- const inst_ty = f.air.typeOfIndex(inst);
const ptr = try f.resolveInst(atomic_load.ptr);
+ const ptr_ty = f.air.typeOf(atomic_load.ptr);
+ if (!ptr_ty.isVolatilePtr() and f.liveness.isUnused(inst))
+ return CValue.none;
+
+ const inst_ty = f.air.typeOfIndex(inst);
const local = try f.allocLocal(inst_ty, .Const);
const writer = f.object.writer();
@@ -2036,6 +2042,44 @@ fn airAtomicStore(f: *Function, inst: Air.Inst.Index, order: [*:0]const u8) !CVa
return local;
}
+fn airMemset(f: *Function, inst: Air.Inst.Index) !CValue {
+ const pl_op = f.air.instructions.items(.data)[inst].pl_op;
+ const extra = f.air.extraData(Air.Bin, pl_op.payload).data;
+ const dest_ptr = try f.resolveInst(pl_op.operand);
+ const value = try f.resolveInst(extra.lhs);
+ const len = try f.resolveInst(extra.rhs);
+ const writer = f.object.writer();
+
+ try writer.writeAll("memset(");
+ try f.writeCValue(writer, dest_ptr);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, value);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, len);
+ try writer.writeAll(");\n");
+
+ return CValue.none;
+}
+
+fn airMemcpy(f: *Function, inst: Air.Inst.Index) !CValue {
+ const pl_op = f.air.instructions.items(.data)[inst].pl_op;
+ const extra = f.air.extraData(Air.Bin, pl_op.payload).data;
+ const dest_ptr = try f.resolveInst(pl_op.operand);
+ const src_ptr = try f.resolveInst(extra.lhs);
+ const len = try f.resolveInst(extra.rhs);
+ const writer = f.object.writer();
+
+ try writer.writeAll("memcpy(");
+ try f.writeCValue(writer, dest_ptr);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, src_ptr);
+ try writer.writeAll(", ");
+ try f.writeCValue(writer, len);
+ try writer.writeAll(");\n");
+
+ return CValue.none;
+}
+
fn toMemoryOrder(order: std.builtin.AtomicOrder) [:0]const u8 {
return switch (order) {
.Unordered => "memory_order_relaxed",
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index b2b87b97d8..b15834c963 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -1279,6 +1279,8 @@ pub const FuncGen = struct {
.fence => try self.airFence(inst),
.atomic_rmw => try self.airAtomicRmw(inst),
.atomic_load => try self.airAtomicLoad(inst),
+ .memset => try self.airMemset(inst),
+ .memcpy => try self.airMemcpy(inst),
.atomic_store_unordered => try self.airAtomicStore(inst, .Unordered),
.atomic_store_monotonic => try self.airAtomicStore(inst, .Monotonic),
@@ -2426,6 +2428,8 @@ pub const FuncGen = struct {
const atomic_load = self.air.instructions.items(.data)[inst].atomic_load;
const ptr = try self.resolveInst(atomic_load.ptr);
const ptr_ty = self.air.typeOf(atomic_load.ptr);
+ if (!ptr_ty.isVolatilePtr() and self.liveness.isUnused(inst))
+ return null;
const ordering = toLlvmAtomicOrdering(atomic_load.order);
const operand_ty = ptr_ty.elemType();
const opt_abi_ty = self.dg.getAtomicAbiType(operand_ty, false);
@@ -2468,6 +2472,55 @@ pub const FuncGen = struct {
return null;
}
+ fn airMemset(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
+ const dest_ptr = try self.resolveInst(pl_op.operand);
+ const ptr_ty = self.air.typeOf(pl_op.operand);
+ const value = try self.resolveInst(extra.lhs);
+ const val_is_undef = if (self.air.value(extra.lhs)) |val| val.isUndef() else false;
+ const len = try self.resolveInst(extra.rhs);
+ const u8_llvm_ty = self.context.intType(8);
+ const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0);
+ const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");
+ const fill_char = if (val_is_undef) u8_llvm_ty.constInt(0xaa, .False) else value;
+ const target = self.dg.module.getTarget();
+ const dest_ptr_align = ptr_ty.ptrAlignment(target);
+ const memset = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align);
+ memset.setVolatile(llvm.Bool.fromBool(ptr_ty.isVolatilePtr()));
+
+ if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {
+ // TODO generate valgrind client request to mark byte range as undefined
+ // see gen_valgrind_undef() in codegen.cpp
+ }
+ return null;
+ }
+
+ fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
+ const pl_op = self.air.instructions.items(.data)[inst].pl_op;
+ const extra = self.air.extraData(Air.Bin, pl_op.payload).data;
+ const dest_ptr = try self.resolveInst(pl_op.operand);
+ const dest_ptr_ty = self.air.typeOf(pl_op.operand);
+ const src_ptr = try self.resolveInst(extra.lhs);
+ const src_ptr_ty = self.air.typeOf(extra.lhs);
+ const len = try self.resolveInst(extra.rhs);
+ const u8_llvm_ty = self.context.intType(8);
+ const ptr_u8_llvm_ty = u8_llvm_ty.pointerType(0);
+ const dest_ptr_u8 = self.builder.buildBitCast(dest_ptr, ptr_u8_llvm_ty, "");
+ const src_ptr_u8 = self.builder.buildBitCast(src_ptr, ptr_u8_llvm_ty, "");
+ const is_volatile = src_ptr_ty.isVolatilePtr() or dest_ptr_ty.isVolatilePtr();
+ const target = self.dg.module.getTarget();
+ const memcpy = self.builder.buildMemCpy(
+ dest_ptr_u8,
+ dest_ptr_ty.ptrAlignment(target),
+ src_ptr_u8,
+ src_ptr_ty.ptrAlignment(target),
+ len,
+ );
+ memcpy.setVolatile(llvm.Bool.fromBool(is_volatile));
+ return null;
+ }
+
fn getIntrinsic(self: *FuncGen, name: []const u8) *const llvm.Value {
const id = llvm.lookupIntrinsicID(name.ptr, name.len);
assert(id != 0);
diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig
index c53ac08fdd..9d32682260 100644
--- a/src/codegen/llvm/bindings.zig
+++ b/src/codegen/llvm/bindings.zig
@@ -632,6 +632,25 @@ pub const Builder = opaque {
DestTy: *const Type,
Name: [*:0]const u8,
) *const Value;
+
+ pub const buildMemSet = LLVMBuildMemSet;
+ extern fn LLVMBuildMemSet(
+ B: *const Builder,
+ Ptr: *const Value,
+ Val: *const Value,
+ Len: *const Value,
+ Align: c_uint,
+ ) *const Value;
+
+ pub const buildMemCpy = LLVMBuildMemCpy;
+ extern fn LLVMBuildMemCpy(
+ B: *const Builder,
+ Dst: *const Value,
+ DstAlign: c_uint,
+ Src: *const Value,
+ SrcAlign: c_uint,
+ Size: *const Value,
+ ) *const Value;
};
pub const IntPredicate = enum(c_uint) {