| ... | ... | @@ -643,67 +643,21 @@ pub const DeclGen = struct { |
| 643 | 643 | llvm_fn.setUnnamedAddr(.True); |
| 644 | 644 | } |
| 645 | 645 | |
| 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 | 655 | // TODO: more attributes. see codegen.cpp `make_fn_llvm_value`. |
| 647 | 656 | 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)); |
| 707 | 661 | } |
| 708 | 662 | |
| 709 | 663 | // Function attributes that are independent of analysis results of the function body. |
| ... | ... | @@ -1445,6 +1399,7 @@ pub const FuncGen = struct { |
| 1445 | 1399 | const zig_fn_type = self.air.typeOf(pl_op.operand); |
| 1446 | 1400 | const return_type = zig_fn_type.fnReturnType(); |
| 1447 | 1401 | const llvm_fn = try self.resolveInst(pl_op.operand); |
| 1402 | const target = self.dg.module.getTarget(); |
| 1448 | 1403 | |
| 1449 | 1404 | const llvm_param_vals = try self.gpa.alloc(*const llvm.Value, args.len); |
| 1450 | 1405 | defer self.gpa.free(llvm_param_vals); |
| ... | ... | @@ -1457,6 +1412,8 @@ pub const FuncGen = struct { |
| 1457 | 1412 | llvm_fn, |
| 1458 | 1413 | llvm_param_vals.ptr, |
| 1459 | 1414 | @intCast(c_uint, args.len), |
| 1415 | toLlvmCallConv(zig_fn_type.fnCallingConvention(), target), |
| 1416 | .Auto, |
| 1460 | 1417 | "", |
| 1461 | 1418 | ); |
| 1462 | 1419 | |
| ... | ... | @@ -1489,13 +1446,10 @@ pub const FuncGen = struct { |
| 1489 | 1446 | const lhs = try self.resolveInst(bin_op.lhs); |
| 1490 | 1447 | const rhs = try self.resolveInst(bin_op.rhs); |
| 1491 | 1448 | const operand_ty = self.air.typeOf(bin_op.lhs); |
| 1449 | var buffer: Type.Payload.Bits = undefined; |
| 1492 | 1450 | |
| 1493 | 1451 | 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), |
| 1499 | 1453 | .Int, .Bool, .Pointer, .ErrorSet => operand_ty, |
| 1500 | 1454 | .Float => { |
| 1501 | 1455 | const operation: llvm.RealPredicate = switch (op) { |
| ... | ... | @@ -1511,13 +1465,13 @@ pub const FuncGen = struct { |
| 1511 | 1465 | else => unreachable, |
| 1512 | 1466 | }; |
| 1513 | 1467 | const is_signed = int_ty.isSignedInt(); |
| 1514 | | const operation = switch (op) { |
| 1468 | const operation: llvm.IntPredicate = switch (op) { |
| 1515 | 1469 | .eq => .EQ, |
| 1516 | 1470 | .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, |
| 1521 | 1475 | }; |
| 1522 | 1476 | return self.builder.buildICmp(operation, lhs, rhs, ""); |
| 1523 | 1477 | } |
| ... | ... | @@ -1947,6 +1901,8 @@ pub const FuncGen = struct { |
| 1947 | 1901 | asm_fn, |
| 1948 | 1902 | llvm_param_values.ptr, |
| 1949 | 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 | 2517 | fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value { |
| 2562 | 2518 | _ = inst; |
| 2563 | 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 | 2521 | return null; |
| 2566 | 2522 | } |
| 2567 | 2523 | |
| ... | ... | @@ -2818,7 +2774,7 @@ pub const FuncGen = struct { |
| 2818 | 2774 | }; |
| 2819 | 2775 | |
| 2820 | 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 | 2778 | const result_ty = self.air.typeOfIndex(inst); |
| 2823 | 2779 | const result_llvm_ty = try self.dg.llvmType(result_ty); |
| 2824 | 2780 | const result_bits = result_ty.intInfo(target).bits; |
| ... | ... | @@ -3108,6 +3064,32 @@ fn toLlvmAtomicRmwBinOp( |
| 3108 | 3064 | }; |
| 3109 | 3065 | } |
| 3110 | 3066 | |
| 3067 | fn 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 | 3093 | /// Take into account 0 bit fields. |
| 3112 | 3094 | fn llvmFieldIndex(ty: Type, index: u32) c_uint { |
| 3113 | 3095 | const struct_obj = ty.castTag(.@"struct").?.data; |