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 {...@@ -32,7 +32,7 @@ pub inline fn cmp(comptime T: type, comptime RT: type, a: T, b: T) RT {
32 const exponentBits = std.math.floatExponentBits(T);32 const exponentBits = std.math.floatExponentBits(T);
33 const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));33 const signBit = (@as(rep_t, 1) << (significandBits + exponentBits));
34 const absMask = signBit - 1;34 const absMask = signBit - 1;
35 const infT = std.math.inf(T);35 const infT = comptime std.math.inf(T);
36 const infRep = @bitCast(rep_t, infT);36 const infRep = @bitCast(rep_t, infT);
3737
38 const aInt = @bitCast(srep_t, a);38 const aInt = @bitCast(srep_t, a);
src/codegen/llvm.zig+53-71
...@@ -643,67 +643,21 @@ pub const DeclGen = struct {...@@ -643,67 +643,21 @@ pub const DeclGen = struct {
643 llvm_fn.setUnnamedAddr(.True);643 llvm_fn.setUnnamedAddr(.True);
644 }644 }
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
646 // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`.655 // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`.
647 const target = self.module.getTarget();656 const target = self.module.getTarget();
648 switch (fn_info.cc) {657 if (fn_info.cc == .Naked) {
649 .Unspecified, .Inline, .Async => {658 self.addFnAttr(llvm_fn, "naked");
650 llvm_fn.setFunctionCallConv(.Fast);659 } else {
651 },660 llvm_fn.setFunctionCallConv(toLlvmCallConv(fn_info.cc, target));
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 },
707 }661 }
708662
709 // Function attributes that are independent of analysis results of the function body.663 // Function attributes that are independent of analysis results of the function body.
...@@ -1445,6 +1399,7 @@ pub const FuncGen = struct {...@@ -1445,6 +1399,7 @@ pub const FuncGen = struct {
1445 const zig_fn_type = self.air.typeOf(pl_op.operand);1399 const zig_fn_type = self.air.typeOf(pl_op.operand);
1446 const return_type = zig_fn_type.fnReturnType();1400 const return_type = zig_fn_type.fnReturnType();
1447 const llvm_fn = try self.resolveInst(pl_op.operand);1401 const llvm_fn = try self.resolveInst(pl_op.operand);
1402 const target = self.dg.module.getTarget();
14481403
1449 const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len);1404 const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len);
1450 defer self.gpa.free(llvm_param_vals);1405 defer self.gpa.free(llvm_param_vals);
...@@ -1457,6 +1412,8 @@ pub const FuncGen = struct {...@@ -1457,6 +1412,8 @@ pub const FuncGen = struct {
1457 llvm_fn,1412 llvm_fn,
1458 llvm_param_vals.ptr,1413 llvm_param_vals.ptr,
1459 @intCast(c_uint, args.len),1414 @intCast(c_uint, args.len),
1415 toLlvmCallConv(zig_fn_type.fnCallingConvention(), target),
1416 .Auto,
1460 "",1417 "",
1461 );1418 );
14621419
...@@ -1489,13 +1446,10 @@ pub const FuncGen = struct {...@@ -1489,13 +1446,10 @@ pub const FuncGen = struct {
1489 const lhs = try self.resolveInst(bin_op.lhs);1446 const lhs = try self.resolveInst(bin_op.lhs);
1490 const rhs = try self.resolveInst(bin_op.rhs);1447 const rhs = try self.resolveInst(bin_op.rhs);
1491 const operand_ty = self.air.typeOf(bin_op.lhs);1448 const operand_ty = self.air.typeOf(bin_op.lhs);
1449 var buffer: Type.Payload.Bits = undefined;
14921450
1493 const int_ty = switch (operand_ty.zigTypeTag()) {1451 const int_ty = switch (operand_ty.zigTypeTag()) {
1494 .Enum => blk: {1452 .Enum => operand_ty.intTagType(&buffer),
1495 var buffer: Type.Payload.Bits = undefined;
1496 const int_ty = operand_ty.intTagType(&buffer);
1497 break :blk int_ty;
1498 },
1499 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,1453 .Int, .Bool, .Pointer, .ErrorSet => operand_ty,
1500 .Float => {1454 .Float => {
1501 const operation: llvm.RealPredicate = switch (op) {1455 const operation: llvm.RealPredicate = switch (op) {
...@@ -1511,13 +1465,13 @@ pub const FuncGen = struct {...@@ -1511,13 +1465,13 @@ pub const FuncGen = struct {
1511 else => unreachable,1465 else => unreachable,
1512 };1466 };
1513 const is_signed = int_ty.isSignedInt();1467 const is_signed = int_ty.isSignedInt();
1514 const operation = switch (op) {1468 const operation: llvm.IntPredicate = switch (op) {
1515 .eq => .EQ,1469 .eq => .EQ,
1516 .neq => .NE,1470 .neq => .NE,
1517 .lt => @as(llvm.IntPredicate, if (is_signed) .SLT else .ULT),1471 .lt => if (is_signed) llvm.IntPredicate.SLT else .ULT,
1518 .lte => @as(llvm.IntPredicate, if (is_signed) .SLE else .ULE),1472 .lte => if (is_signed) llvm.IntPredicate.SLE else .ULE,
1519 .gt => @as(llvm.IntPredicate, if (is_signed) .SGT else .UGT),1473 .gt => if (is_signed) llvm.IntPredicate.SGT else .UGT,
1520 .gte => @as(llvm.IntPredicate, if (is_signed) .SGE else .UGE),1474 .gte => if (is_signed) llvm.IntPredicate.SGE else .UGE,
1521 };1475 };
1522 return self.builder.buildICmp(operation, lhs, rhs, "");1476 return self.builder.buildICmp(operation, lhs, rhs, "");
1523 }1477 }
...@@ -1947,6 +1901,8 @@ pub const FuncGen = struct {...@@ -1947,6 +1901,8 @@ pub const FuncGen = struct {
1947 asm_fn,1901 asm_fn,
1948 llvm_param_values.ptr,1902 llvm_param_values.ptr,
1949 @intCast(c_uint, llvm_param_values.len),1903 @intCast(c_uint, llvm_param_values.len),
1904 .C,
1905 .Auto,
1950 "",1906 "",
1951 );1907 );
1952 }1908 }
...@@ -2561,7 +2517,7 @@ pub const FuncGen = struct {...@@ -2561,7 +2517,7 @@ pub const FuncGen = struct {
2561 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {2517 fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
2562 _ = inst;2518 _ = inst;
2563 const llvm_fn = self.getIntrinsic("llvm.debugtrap");2519 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, "");
2565 return null;2521 return null;
2566 }2522 }
25672523
...@@ -2818,7 +2774,7 @@ pub const FuncGen = struct {...@@ -2818,7 +2774,7 @@ pub const FuncGen = struct {
2818 };2774 };
28192775
2820 const params = [_]*const llvm.Value{ operand, llvm_i1.constNull() };2776 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, "");
2822 const result_ty = self.air.typeOfIndex(inst);2778 const result_ty = self.air.typeOfIndex(inst);
2823 const result_llvm_ty = try self.dg.llvmType(result_ty);2779 const result_llvm_ty = try self.dg.llvmType(result_ty);
2824 const result_bits = result_ty.intInfo(target).bits;2780 const result_bits = result_ty.intInfo(target).bits;
...@@ -3108,6 +3064,32 @@ fn toLlvmAtomicRmwBinOp(...@@ -3108,6 +3064,32 @@ fn toLlvmAtomicRmwBinOp(
3108 };3064 };
3109}3065}
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
3111/// Take into account 0 bit fields.3093/// Take into account 0 bit fields.
3112fn llvmFieldIndex(ty: Type, index: u32) c_uint {3094fn llvmFieldIndex(ty: Type, index: u32) c_uint {
3113 const struct_obj = ty.castTag(.@"struct").?.data;3095 const struct_obj = ty.castTag(.@"struct").?.data;
src/codegen/llvm/bindings.zig+12-12
...@@ -359,22 +359,14 @@ pub const Builder = opaque {...@@ -359,22 +359,14 @@ pub const Builder = opaque {
359 Name: [*:0]const u8,359 Name: [*:0]const u8,
360 ) *const Value;360 ) *const Value;
361361
362 pub const buildCall = LLVMBuildCall;362 pub const buildCall = ZigLLVMBuildCall;
363 extern fn LLVMBuildCall(363 extern fn ZigLLVMBuildCall(
364 *const Builder,364 *const Builder,
365 Fn: *const Value,365 Fn: *const Value,
366 Args: [*]const *const Value,366 Args: [*]const *const Value,
367 NumArgs: c_uint,367 NumArgs: c_uint,
368 Name: [*:0]const u8,368 CC: CallConv,
369 ) *const Value;369 attr: CallAttr,
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,
378 Name: [*:0]const u8,370 Name: [*:0]const u8,
379 ) *const Value;371 ) *const Value;
380372
...@@ -1184,6 +1176,14 @@ pub const CallConv = enum(c_uint) {...@@ -1184,6 +1176,14 @@ pub const CallConv = enum(c_uint) {
1184 AArch64_VectorCall = 97,1176 AArch64_VectorCall = 97,
1185};1177};
11861178
1179pub const CallAttr = enum(c_int) {
1180 Auto,
1181 NeverTail,
1182 NeverInline,
1183 AlwaysTail,
1184 AlwaysInline,
1185};
1186
1187pub const address_space = struct {1187pub const address_space = struct {
1188 pub const default: c_uint = 0;1188 pub const default: c_uint = 0;
11891189