| ... | @@ -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 case | 4019 | /// 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 parameters | 4025 | /// 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 undefined | 7536 | 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()); |
| 7791 | | 7793 | |
| 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 undefined | 7795 | 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 | }; |
| 9102 | | 9186 | |
| 9103 | fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void { | 9187 | fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void { |