Skip to content

Commit

Permalink
LLVM: implement signext/zeroext attributes
Browse files Browse the repository at this point in the history
For calling convention ABI purposes, integer attributes and return
values need to have an LLVM attribute signext or zeroext added
sometimes. This commit implements that logic.

It also implements a proof-of-concept of moving the F16T type from
being a compiler_rt hack to being how the compiler lowers f16 in
functions that need to match certain calling conventions.

Closes #12054
  • Loading branch information
andrewrk committed Jul 13, 2022
1 parent a66a9b2 commit 20458b1
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 32 deletions.
6 changes: 5 additions & 1 deletion lib/compiler_rt/common.zig
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,11 @@ pub fn panic(msg: []const u8, error_return_trace: ?*std.builtin.StackTrace) nore
/// need for extending them to wider fp types.
/// TODO remove this; do this type selection in the language rather than
/// here in compiler-rt.
pub const F16T = if (builtin.cpu.arch.isAARCH64()) f16 else u16;
pub const F16T = switch (builtin.cpu.arch) {
.aarch64, .aarch64_be, .aarch64_32 => f16,
.riscv64 => if (builtin.zig_backend == .stage1) u16 else f16,
else => u16,
};

pub fn wideMultiply(comptime Z: type, a: Z, b: Z, hi: *Z, lo: *Z) void {
switch (Z) {
Expand Down
65 changes: 64 additions & 1 deletion src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,11 @@ pub const Object = struct {
const ret_ptr = if (sret) llvm_func.getParam(0) else null;
const gpa = dg.gpa;

if (ccAbiPromoteInt(fn_info.cc, target, fn_info.return_type)) |s| switch (s) {
.signed => dg.addAttr(llvm_func, 0, "signext"),
.unsigned => dg.addAttr(llvm_func, 0, "zeroext"),
};

const err_return_tracing = fn_info.return_type.isError() and
dg.module.comp.bin_file.options.error_return_tracing;

Expand Down Expand Up @@ -774,7 +779,10 @@ pub const Object = struct {
);
dg.addArgAttrInt(llvm_func, llvm_arg_i, "align", elem_align);
}
}
} else if (ccAbiPromoteInt(fn_info.cc, target, param_ty)) |s| switch (s) {
.signed => dg.addArgAttr(llvm_func, llvm_arg_i, "signext"),
.unsigned => dg.addArgAttr(llvm_func, llvm_arg_i, "zeroext"),
};
}
llvm_arg_i += 1;
},
Expand Down Expand Up @@ -887,6 +895,13 @@ pub const Object = struct {
};
try args.append(loaded);
},
.as_u16 => {
const param = llvm_func.getParam(llvm_arg_i);
llvm_arg_i += 1;
const casted = builder.buildBitCast(param, dg.context.halfType(), "");
try args.ensureUnusedCapacity(1);
args.appendAssumeCapacity(casted);
},
};
}

Expand Down Expand Up @@ -2794,6 +2809,9 @@ pub const DeclGen = struct {
llvm_params.appendAssumeCapacity(big_int_ty);
}
},
.as_u16 => {
try llvm_params.append(dg.context.intType(16));
},
};

return llvm.functionType(
Expand Down Expand Up @@ -4234,6 +4252,12 @@ pub const FuncGen = struct {
llvm_args.appendAssumeCapacity(load_inst);
}
},
.as_u16 => {
const arg = args[it.zig_index - 1];
const llvm_arg = try self.resolveInst(arg);
const casted = self.builder.buildBitCast(llvm_arg, self.dg.context.intType(16), "");
try llvm_args.append(casted);
},
};

const call = self.builder.buildCall(
Expand Down Expand Up @@ -8965,6 +8989,7 @@ const ParamTypeIterator = struct {
abi_sized_int,
multiple_llvm_ints,
slice,
as_u16,
};

pub fn next(it: *ParamTypeIterator) ?Lowering {
Expand Down Expand Up @@ -9025,6 +9050,15 @@ const ParamTypeIterator = struct {
else => false,
};
switch (it.target.cpu.arch) {
.riscv32, .riscv64 => {
it.zig_index += 1;
it.llvm_index += 1;
if (ty.tag() == .f16) {
return .as_u16;
} else {
return .byval;
}
},
.mips, .mipsel => {
it.zig_index += 1;
it.llvm_index += 1;
Expand Down Expand Up @@ -9135,6 +9169,35 @@ fn iterateParamTypes(dg: *DeclGen, fn_info: Type.Payload.Function.Data) ParamTyp
};
}

fn ccAbiPromoteInt(
cc: std.builtin.CallingConvention,
target: std.Target,
ty: Type,
) ?std.builtin.Signedness {
switch (cc) {
.Unspecified, .Inline, .Async => return null,
else => {},
}
const int_info = switch (ty.zigTypeTag()) {
.Int, .Enum, .ErrorSet => ty.intInfo(target),
else => return null,
};
if (int_info.bits <= 16) return int_info.signedness;
switch (target.cpu.arch) {
.sparc64,
.riscv64,
.powerpc64,
.powerpc64le,
=> {
if (int_info.bits < 64) {
return int_info.signedness;
}
},
else => {},
}
return null;
}

fn isByRef(ty: Type) bool {
// For tuples and structs, if there are more than this many non-void
// fields, then we make it byref, otherwise byval.
Expand Down
30 changes: 0 additions & 30 deletions test/behavior/math.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1168,11 +1168,6 @@ test "remainder division" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO

if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
// https://github.com/ziglang/zig/issues/12054
return error.SkipZigTest;
}

comptime try remdiv(f16);
comptime try remdiv(f32);
comptime try remdiv(f64);
Expand Down Expand Up @@ -1204,11 +1199,6 @@ test "float remainder division using @rem" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO

if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
// https://github.com/ziglang/zig/issues/12054
return error.SkipZigTest;
}

comptime try frem(f16);
comptime try frem(f32);
comptime try frem(f64);
Expand Down Expand Up @@ -1251,11 +1241,6 @@ test "float modulo division using @mod" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO

if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
// https://github.com/ziglang/zig/issues/12054
return error.SkipZigTest;
}

comptime try fmod(f16);
comptime try fmod(f32);
comptime try fmod(f64);
Expand Down Expand Up @@ -1431,11 +1416,6 @@ test "@ceil f80" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO

if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
// https://github.com/ziglang/zig/issues/12054
return error.SkipZigTest;
}

try testCeil(f80, 12.0);
comptime try testCeil(f80, 12.0);
}
Expand All @@ -1447,11 +1427,6 @@ test "@ceil f128" {
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO

if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
// https://github.com/ziglang/zig/issues/12054
return error.SkipZigTest;
}

try testCeil(f128, 12.0);
comptime try testCeil(f128, 12.0);
}
Expand Down Expand Up @@ -1600,11 +1575,6 @@ test "NaN comparison" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO

if (builtin.zig_backend == .stage2_llvm and builtin.cpu.arch == .riscv64) {
// https://github.com/ziglang/zig/issues/12054
return error.SkipZigTest;
}

try testNanEqNan(f16);
try testNanEqNan(f32);
try testNanEqNan(f64);
Expand Down

0 comments on commit 20458b1

Please sign in to comment.