authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-05 20:28:29-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-05 20:36:04-07:00
log9ed599b4e3f5c9f48089a3acd61d0338e27e88f6
tree97f51ac789f90050f659b3faceb4a665aa304868
parent01ad6c0b020193a6c5c82e13296a12e847f78d05

stage2: LLVM backend: miscompilation fixes

* work around a stage1 miscompilation leading to the wrong integer comparison predicate being emitted. * fix the bug of not annotating callsites with the calling convention of the callee, leading to undefined behavior. * add the `nobuiltin` attribute when building freestanding libc or compiler_rt libraries to prevent e.g. memcpy from being "optimized" into a call to itself. * compiler-rt: change a call to be comptime to make the generated LLVM IR simpler and easier to study. I still can't enable the widening tests due to the compiler-rt compare function being miscompiled in some not-yet-diagnosed way.

3 files changed, 66 insertions(+), 84 deletions(-)

lib/std/special/compiler_rt/compareXf2.zig+1-1
......@@ -32,7 +32,7 @@ pub inline fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT {
3232 const exponentBits = std.math.floatExponentBits(T);
3333 const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
3434 const absMask = signBit - 1;
35 const infT = std.math.inf(T);
35 const infT = comptime std.math.inf(T);
3636 const infRep = @bitCast(rep_t, infT);
3737
3838 const aInt = @bitCast(srep_t, a);
src/codegen/llvm.zig+53-71
......@@ -643,67 +643,21 @@ pub const DeclGen = struct {
643643 llvm_fn.setUnnamedAddr(.True);
644644 }
645645
646 if (self.module.comp.bin_file.options.skip_linker_dependencies) {
647 // The intent here is for compiler-rt and libc functions to not generate
648 // infinite recursion. For example, if we are compiling the memcpy function,
649 // and llvm detects that the body is equivalent to memcpy, it may replace the
650 // body of memcpy with a call to memcpy, which would then cause a stack
651 // overflow instead of performing memcpy.
652 self.addFnAttr(llvm_fn, "nobuiltin");
653 }
654
646655 // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`.
647656 const target = self.module.getTarget();
648 switch (fn_info.cc) {
649 .Unspecified, .Inline, .Async => {
650 llvm_fn.setFunctionCallConv(.Fast);
651 },
652 .C => {
653 llvm_fn.setFunctionCallConv(.C);
654 },
655 .Naked => {
656 self.addFnAttr(llvm_fn, "naked");
657 },
658 .Stdcall => {
659 llvm_fn.setFunctionCallConv(.X86_StdCall);
660 },
661 .Fastcall => {
662 llvm_fn.setFunctionCallConv(.X86_FastCall);
663 },
664 .Vectorcall => {
665 switch (target.cpu.arch) {
666 .i386, .x86_64 => {
667 llvm_fn.setFunctionCallConv(.X86_VectorCall);
668 },
669 .aarch64, .aarch64_be, .aarch64_32 => {
670 llvm_fn.setFunctionCallConv(.AArch64_VectorCall);
671 },
672 else => unreachable,
673 }
674 },
675 .Thiscall => {
676 llvm_fn.setFunctionCallConv(.X86_ThisCall);
677 },
678 .APCS => {
679 llvm_fn.setFunctionCallConv(.ARM_APCS);
680 },
681 .AAPCS => {
682 llvm_fn.setFunctionCallConv(.ARM_AAPCS);
683 },
684 .AAPCSVFP => {
685 llvm_fn.setFunctionCallConv(.ARM_AAPCS_VFP);
686 },
687 .Interrupt => {
688 switch (target.cpu.arch) {
689 .i386, .x86_64 => {
690 llvm_fn.setFunctionCallConv(.X86_INTR);
691 },
692 .avr => {
693 llvm_fn.setFunctionCallConv(.AVR_INTR);
694 },
695 .msp430 => {
696 llvm_fn.setFunctionCallConv(.MSP430_INTR);
697 },
698 else => unreachable,
699 }
700 },
701 .Signal => {
702 llvm_fn.setFunctionCallConv(.AVR_SIGNAL);
703 },
704 .SysV => {
705 llvm_fn.setFunctionCallConv(.X86_64_SysV);
706 },
657 if (fn_info.cc == .Naked) {
658 self.addFnAttr(llvm_fn, "naked");
659 } else {
660 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
707661 }
708662
709663 // Function attributes that are independent of analysis results of the function body.
......@@ -1445,6 +1399,7 @@ pub const FuncGen = struct {
14451399 const zig_fn_type = self.air.typeOf(pl_op.operand);
14461400 const return_type = zig_fn_type.fnReturnType();
14471401 const llvm_fn = try self.resolveInst(pl_op.operand);
1402 const target = self.dg.module.getTarget();
14481403
14491404 const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len);
14501405 defer self.gpa.free(llvm_param_vals);
......@@ -1457,6 +1412,8 @@ pub const FuncGen = struct {
14571412 llvm_fn,
14581413 llvm_param_vals.ptr,
14591414 @intCast(c_uint, args.len),
1415 toLlvmCallConv(zig_fn_type.fnCallingConvention(), target),
1416 .Auto,
14601417 "",
14611418 );
14621419
......@@ -1489,13 +1446,10 @@ pub const FuncGen = struct {
14891446 const lhs = try self.resolveInst(bin_op.lhs);
14901447 const rhs = try self.resolveInst(bin_op.rhs);
14911448 const operand_ty = self.air.typeOf(bin_op.lhs);
1449 var buffer: Type.Payload.Bits = undefined;
14921450
14931451 const int_ty = switch (operand_ty.zigTypeTag()) {
1494 .Enum => blk: {
1495 var buffer: Type.Payload.Bits = undefined;
1496 const int_ty = operand_ty.intTagType(&buffer);
1497 break :blk int_ty;
1498 },
1452 .Enum => operand_ty.intTagType(&buffer),
14991453 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,
15001454 .Float => {
15011455 const operation: llvm.RealPredicate = switch (op) {
......@@ -1511,13 +1465,13 @@ pub const FuncGen = struct {
15111465 else => unreachable,
15121466 };
15131467 const is_signed = int_ty.isSignedInt();
1514 const operation = switch (op) {
1468 const operation: llvm.IntPredicate = switch (op) {
15151469 .eq => .EQ,
15161470 .neq => .NE,
1517 .lt => @as(llvm.IntPredicate, if (is_signed) .SLT else .ULT),
1518 .lte => @as(llvm.IntPredicate, if (is_signed) .SLE else .ULE),
1519 .gt => @as(llvm.IntPredicate, if (is_signed) .SGT else .UGT),
1520 .gte => @as(llvm.IntPredicate, if (is_signed) .SGE else .UGE),
1471 .lt => if (is_signed) llvm.IntPredicate.SLT else .ULT,
1472 .lte => if (is_signed) llvm.IntPredicate.SLE else .ULE,
1473 .gt => if (is_signed) llvm.IntPredicate.SGT else .UGT,
1474 .gte => if (is_signed) llvm.IntPredicate.SGE else .UGE,
15211475 };
15221476 return self.builder.buildICmp(operation, lhs, rhs, "");
15231477 }
......@@ -1947,6 +1901,8 @@ pub const FuncGen = struct {
19471901 asm_fn,
19481902 llvm_param_values.ptr,
19491903 @intCast(c_uint, llvm_param_values.len),
1904 .C,
1905 .Auto,
19501906 "",
19511907 );
19521908 }
......@@ -2561,7 +2517,7 @@ pub const FuncGen = struct {
25612517 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
25622518 _ = inst;
25632519 const llvm_fn = self.getIntrinsic("llvm.debugtrap");
2564 _ = self.builder.buildCall(llvm_fn, undefined, 0, "");
2520 _ = self.builder.buildCall(llvm_fn, undefined, 0, .C, .Auto, "");
25652521 return null;
25662522 }
25672523
......@@ -2818,7 +2774,7 @@ pub const FuncGen = struct {
28182774 };
28192775
28202776 const params = [_]*const llvm.Value{ operand, llvm_i1.constNull() };
2821 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, "");
2777 const wrong_size_result = self.builder.buildCall(fn_val, &params, params.len, .C, .Auto, "");
28222778 const result_ty = self.air.typeOfIndex(inst);
28232779 const result_llvm_ty = try self.dg.llvmType(result_ty);
28242780 const result_bits = result_ty.intInfo(target).bits;
......@@ -3108,6 +3064,32 @@ fn toLlvmAtomicRmwBinOp(
31083064 };
31093065}
31103066
3067fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.CallConv {
3068 return switch (cc) {
3069 .Unspecified, .Inline, .Async => .Fast,
3070 .C, .Naked => .C,
3071 .Stdcall => .X86_StdCall,
3072 .Fastcall => .X86_FastCall,
3073 .Vectorcall => return switch (target.cpu.arch) {
3074 .i386, .x86_64 => .X86_VectorCall,
3075 .aarch64, .aarch64_be, .aarch64_32 => .AArch64_VectorCall,
3076 else => unreachable,
3077 },
3078 .Thiscall => .X86_ThisCall,
3079 .APCS => .ARM_APCS,
3080 .AAPCS => .ARM_AAPCS,
3081 .AAPCSVFP => .ARM_AAPCS_VFP,
3082 .Interrupt => return switch (target.cpu.arch) {
3083 .i386, .x86_64 => .X86_INTR,
3084 .avr => .AVR_INTR,
3085 .msp430 => .MSP430_INTR,
3086 else => unreachable,
3087 },
3088 .Signal => .AVR_SIGNAL,
3089 .SysV => .X86_64_SysV,
3090 };
3091}
3092
31113093/// Take into account 0 bit fields.
31123094fn llvmFieldIndex(ty: Type, index: u32) c_uint {
31133095 const struct_obj = ty.castTag(.@"struct").?.data;
src/codegen/llvm/bindings.zig+12-12
......@@ -359,22 +359,14 @@ pub const Builder = opaque {
359359 Name: [*:0]const u8,
360360 ) *const Value;
361361
362 pub const buildCall = LLVMBuildCall;
363 extern fn LLVMBuildCall(
362 pub const buildCall = ZigLLVMBuildCall;
363 extern fn ZigLLVMBuildCall(
364364 *const Builder,
365365 Fn: *const Value,
366366 Args: [*]const *const Value,
367367 NumArgs: c_uint,
368 Name: [*:0]const u8,
369 ) *const Value;
370
371 pub const buildCall2 = LLVMBuildCall2;
372 extern fn LLVMBuildCall2(
373 *const Builder,
374 *const Type,
375 Fn: *const Value,
376 Args: [*]*const Value,
377 NumArgs: c_uint,
368 CC: CallConv,
369 attr: CallAttr,
378370 Name: [*:0]const u8,
379371 ) *const Value;
380372
......@@ -1184,6 +1176,14 @@ pub const CallConv = enum(c_uint) {
11841176 AArch64_VectorCall = 97,
11851177};
11861178
1179pub const CallAttr = enum(c_int) {
1180 Auto,
1181 NeverTail,
1182 NeverInline,
1183 AlwaysTail,
1184 AlwaysInline,
1185};
1186
11871187pub const address_space = struct {
11881188 pub const default: c_uint = 0;
11891189