authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-22 16:04:07-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-22 16:04:07-07:00
logdae7aeb33779d0214c3efe0960af0059416aed51
treedbfc1e38aeb7aaccda48d58d1a5042be2550e4ed
parentecdd4a9fe805c9b5b76cbb883b806ceb61aaddfe

llvm: add valgrind client request integration for x86_64

closes #12500

1 files changed, 88 insertions(+), 4 deletions(-)

src/codegen/llvm.zig+88-4
...@@ -4019,6 +4019,9 @@ pub const FuncGen = struct {...@@ -4019,6 +4019,9 @@ pub const FuncGen = struct {
4019 /// Note that this can disagree with isByRef for the return type in the case4019 /// Note that this can disagree with isByRef for the return type in the case
4020 /// of C ABI functions.4020 /// of C ABI functions.
4021 ret_ptr: ?*const llvm.Value,4021 ret_ptr: ?*const llvm.Value,
4022 /// Any function that needs to perform Valgrind client requests needs an array alloca
4023 /// instruction, however a maximum of one per function is needed.
4024 valgrind_client_request_array: ?*const llvm.Value = null,
4022 /// These fields are used to refer to the LLVM value of the function parameters4025 /// These fields are used to refer to the LLVM value of the function parameters
4023 /// in an Arg instruction.4026 /// in an Arg instruction.
4024 /// This list may be shorter than the list according to the zig type system;4027 /// This list may be shorter than the list according to the zig type system;
...@@ -7530,8 +7533,7 @@ pub const FuncGen = struct {...@@ -7530,8 +7533,7 @@ pub const FuncGen = struct {
7530 const len = usize_llvm_ty.constInt(operand_size, .False);7533 const len = usize_llvm_ty.constInt(operand_size, .False);
7531 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());7534 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
7532 if (self.dg.module.comp.bin_file.options.valgrind) {7535 if (self.dg.module.comp.bin_file.options.valgrind) {
7533 // TODO generate valgrind client request to mark byte range as undefined7536 self.valgrindMarkUndef(dest_ptr, len);
7534 // see gen_valgrind_undef() in codegen.cpp
7535 }7537 }
7536 } else {7538 } else {
7537 const src_operand = try self.resolveInst(bin_op.rhs);7539 const src_operand = try self.resolveInst(bin_op.rhs);
...@@ -7790,8 +7792,7 @@ pub const FuncGen = struct {...@@ -7790,8 +7792,7 @@ pub const FuncGen = struct {
7790 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());7792 _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());
77917793
7792 if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {7794 if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {
7793 // TODO generate valgrind client request to mark byte range as undefined7795 self.valgrindMarkUndef(dest_ptr_u8, len);
7794 // see gen_valgrind_undef() in codegen.cpp
7795 }7796 }
7796 return null;7797 return null;
7797 }7798 }
...@@ -9098,6 +9099,89 @@ pub const FuncGen = struct {...@@ -9098,6 +9099,89 @@ pub const FuncGen = struct {
9098 info.@"volatile",9099 info.@"volatile",
9099 );9100 );
9100 }9101 }
9102
9103 fn valgrindMarkUndef(fg: *FuncGen, ptr: *const llvm.Value, len: *const llvm.Value) void {
9104 const VG_USERREQ__MAKE_MEM_UNDEFINED = 1296236545;
9105 const target = fg.dg.module.getTarget();
9106 const usize_llvm_ty = fg.context.intType(target.cpu.arch.ptrBitWidth());
9107 const zero = usize_llvm_ty.constInt(0, .False);
9108 const req = usize_llvm_ty.constInt(VG_USERREQ__MAKE_MEM_UNDEFINED, .False);
9109 const ptr_as_usize = fg.builder.buildPtrToInt(ptr, usize_llvm_ty, "");
9110 _ = valgrindClientRequest(fg, zero, req, ptr_as_usize, len, zero, zero, zero);
9111 }
9112
9113 fn valgrindClientRequest(
9114 fg: *FuncGen,
9115 default_value: *const llvm.Value,
9116 request: *const llvm.Value,
9117 a1: *const llvm.Value,
9118 a2: *const llvm.Value,
9119 a3: *const llvm.Value,
9120 a4: *const llvm.Value,
9121 a5: *const llvm.Value,
9122 ) *const llvm.Value {
9123 const target = fg.dg.module.getTarget();
9124 if (!target_util.hasValgrindSupport(target)) return default_value;
9125
9126 const usize_llvm_ty = fg.context.intType(target.cpu.arch.ptrBitWidth());
9127 const usize_alignment = @intCast(c_uint, Type.usize.abiSize(target));
9128
9129 switch (target.cpu.arch) {
9130 .x86_64 => {
9131 const array_ptr = fg.valgrind_client_request_array orelse a: {
9132 const array_ptr = fg.buildAlloca(usize_llvm_ty.arrayType(6));
9133 array_ptr.setAlignment(usize_alignment);
9134 fg.valgrind_client_request_array = array_ptr;
9135 break :a array_ptr;
9136 };
9137 const array_elements = [_]*const llvm.Value{ request, a1, a2, a3, a4, a5 };
9138 const zero = usize_llvm_ty.constInt(0, .False);
9139 for (array_elements) |elem, i| {
9140 const indexes = [_]*const llvm.Value{
9141 zero, usize_llvm_ty.constInt(@intCast(c_uint, i), .False),
9142 };
9143 const elem_ptr = fg.builder.buildInBoundsGEP(array_ptr, &indexes, indexes.len, "");
9144 const store_inst = fg.builder.buildStore(elem, elem_ptr);
9145 store_inst.setAlignment(usize_alignment);
9146 }
9147
9148 const asm_template =
9149 \\rolq $$3, %rdi ; rolq $$13, %rdi
9150 \\rolq $$61, %rdi ; rolq $$51, %rdi
9151 \\xchgq %rbx,%rbx
9152 ;
9153
9154 const asm_constraints = "={rdx},{rax},0,~{cc},~{memory}";
9155
9156 const array_ptr_as_usize = fg.builder.buildPtrToInt(array_ptr, usize_llvm_ty, "");
9157 const args = [_]*const llvm.Value{ array_ptr_as_usize, default_value };
9158 const param_types = [_]*const llvm.Type{ usize_llvm_ty, usize_llvm_ty };
9159 const fn_llvm_ty = llvm.functionType(usize_llvm_ty, &param_types, args.len, .False);
9160 const asm_fn = llvm.getInlineAsm(
9161 fn_llvm_ty,
9162 asm_template,
9163 asm_template.len,
9164 asm_constraints,
9165 asm_constraints.len,
9166 .True, // has side effects
9167 .False, // alignstack
9168 .ATT,
9169 .False,
9170 );
9171
9172 const call = fg.builder.buildCall(
9173 asm_fn,
9174 &args,
9175 args.len,
9176 .C,
9177 .Auto,
9178 "",
9179 );
9180 return call;
9181 },
9182 else => unreachable,
9183 }
9184 }
9101};9185};
91029186
9103fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {9187fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void {