| ... | ... | @@ -4019,6 +4019,9 @@ pub const FuncGen = struct { |
| 4019 | 4019 | /// Note that this can disagree with isByRef for the return type in the case |
| 4020 | 4020 | /// of C ABI functions. |
| 4021 | 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 | 4025 | /// These fields are used to refer to the LLVM value of the function parameters |
| 4023 | 4026 | /// in an Arg instruction. |
| 4024 | 4027 | /// This list may be shorter than the list according to the zig type system; |
| ... | ... | @@ -7530,8 +7533,7 @@ pub const FuncGen = struct { |
| 7530 | 7533 | const len = usize_llvm_ty.constInt(operand_size, .False); |
| 7531 | 7534 | _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr()); |
| 7532 | 7535 | if (self.dg.module.comp.bin_file.options.valgrind) { |
| 7533 | | // TODO generate valgrind client request to mark byte range as undefined |
| 7534 | | // see gen_valgrind_undef() in codegen.cpp |
| 7536 | self.valgrindMarkUndef(dest_ptr, len); |
| 7535 | 7537 | } |
| 7536 | 7538 | } else { |
| 7537 | 7539 | const src_operand = try self.resolveInst(bin_op.rhs); |
| ... | ... | @@ -7790,8 +7792,7 @@ pub const FuncGen = struct { |
| 7790 | 7792 | _ = self.builder.buildMemSet(dest_ptr_u8, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr()); |
| 7791 | 7793 | |
| 7792 | 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 |
| 7794 | | // see gen_valgrind_undef() in codegen.cpp |
| 7795 | self.valgrindMarkUndef(dest_ptr_u8, len); |
| 7795 | 7796 | } |
| 7796 | 7797 | return null; |
| 7797 | 7798 | } |
| ... | ... | @@ -9098,6 +9099,89 @@ pub const FuncGen = struct { |
| 9098 | 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 | 9187 | fn initializeLLVMTarget(arch: std.Target.Cpu.Arch) void { |