Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 34 additions & 13 deletions lib/std/zig/AstGen.zig
Original file line number Diff line number Diff line change
Expand Up @@ -9390,24 +9390,25 @@ fn builtinCall(
.embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .embed_file),
.error_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .anyerror_type } }, params[0], .error_name),
.set_runtime_safety => return simpleUnOp(gz, scope, ri, node, coerced_bool_ri, params[0], .set_runtime_safety),
.sqrt => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sqrt),
.sin => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sin),
.cos => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .cos),
.tan => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .tan),
.exp => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .exp),
.exp2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .exp2),
.log => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log),
.log2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log2),
.log10 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log10),
.abs => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .abs),
.floor => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .floor),
.ceil => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ceil),
.trunc => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .trunc),
.round => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .round),
.tag_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .tag_name),
.type_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .type_name),
.Frame => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_type),

.sqrt => return floatUnOp(gz, scope, ri, node, params[0], .sqrt),
.sin => return floatUnOp(gz, scope, ri, node, params[0], .sin),
.cos => return floatUnOp(gz, scope, ri, node, params[0], .cos),
.tan => return floatUnOp(gz, scope, ri, node, params[0], .tan),
.exp => return floatUnOp(gz, scope, ri, node, params[0], .exp),
.exp2 => return floatUnOp(gz, scope, ri, node, params[0], .exp2),
.log => return floatUnOp(gz, scope, ri, node, params[0], .log),
.log2 => return floatUnOp(gz, scope, ri, node, params[0], .log2),
.log10 => return floatUnOp(gz, scope, ri, node, params[0], .log10),
.floor => return floatUnOp(gz, scope, ri, node, params[0], .floor),
.ceil => return floatUnOp(gz, scope, ri, node, params[0], .ceil),
.trunc => return floatUnOp(gz, scope, ri, node, params[0], .trunc),
.round => return floatUnOp(gz, scope, ri, node, params[0], .round),

.int_from_float => return typeCast(gz, scope, ri, node, params[0], .int_from_float, builtin_name),
.float_from_int => return typeCast(gz, scope, ri, node, params[0], .float_from_int, builtin_name),
.ptr_from_int => return typeCast(gz, scope, ri, node, params[0], .ptr_from_int, builtin_name),
Expand Down Expand Up @@ -9860,6 +9861,26 @@ fn simpleUnOp(
return rvalue(gz, ri, result, node);
}

fn floatUnOp(
gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
operand_node: Ast.Node.Index,
tag: Zir.Inst.Tag,
) InnerError!Zir.Inst.Ref {
const result_type = try ri.rl.resultType(gz, node);
const operand_ri: ResultInfo.Loc = if (result_type) |rt| .{
.ty = try gz.addExtendedPayload(.float_op_result_ty, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = rt,
}),
} else .none;
const operand = try expr(gz, scope, .{ .rl = operand_ri }, operand_node);
const result = try gz.addUnNode(tag, operand, node);
return rvalue(gz, ri, result, node);
}

fn negation(
gz: *GenZir,
scope: *Scope,
Expand Down
26 changes: 13 additions & 13 deletions lib/std/zig/AstRlAnnotate.zig
Original file line number Diff line number Diff line change
Expand Up @@ -889,6 +889,19 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
.frame_address => return true,
// These builtins take a single argument with a known result type, but do not consume their
// result pointer.
.sqrt,
.sin,
.cos,
.tan,
.exp,
.exp2,
.log,
.log2,
.log10,
.floor,
.ceil,
.trunc,
.round,
.size_of,
.bit_size_of,
.align_of,
Expand Down Expand Up @@ -918,20 +931,7 @@ fn builtinCall(astrl: *AstRlAnnotate, block: ?*Block, ri: ResultInfo, node: Ast.
// result pointer.
.int_from_ptr,
.int_from_enum,
.sqrt,
.sin,
.cos,
.tan,
.exp,
.exp2,
.log,
.log2,
.log10,
.abs,
.floor,
.ceil,
.trunc,
.round,
.tag_name,
.type_name,
.Frame,
Expand Down
6 changes: 6 additions & 0 deletions lib/std/zig/Zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2111,6 +2111,11 @@ pub const Inst = struct {
/// This instruction is always `noreturn`, however, it is not considered as such by ZIR-level queries. This allows AstGen to assume that
/// any code may have gone here, avoiding false-positive "unreachable code" errors.
astgen_error,
/// Given a type, strips away any error unions or optionals stacked
/// on top and returns the base type. That base type must be a float.
/// For example: Provided with error{Foo}!?f64, returns f64.
/// `operand` is `operand: Air.Inst.Ref`.
float_op_result_ty,

pub const InstData = struct {
opcode: Extended,
Expand Down Expand Up @@ -4436,6 +4441,7 @@ fn findTrackableInner(
.tuple_decl,
.dbg_empty_stmt,
.astgen_error,
.float_op_result_ty,
=> return,

// `@TypeOf` has a body.
Expand Down
4 changes: 4 additions & 0 deletions src/Air.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1154,6 +1154,10 @@ pub const Inst = struct {
pub fn fromValue(v: Value) Ref {
return .fromIntern(v.toIntern());
}

pub fn fromType(t: Type) Ref {
return .fromIntern(t.toIntern());
}
};

/// All instructions have an 8-byte payload, which is contained within
Expand Down
23 changes: 23 additions & 0 deletions src/Sema.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1468,6 +1468,7 @@ fn analyzeBodyInner(
continue;
},
.astgen_error => return error.AnalysisFail,
.float_op_result_ty => try sema.zirFloatOpResultType(block, extended),
};
},

Expand Down Expand Up @@ -25921,6 +25922,28 @@ fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
}
}

fn zirFloatOpResultType(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const operand_src = block.builtinCallArgSrc(extra.node, 0);

const raw_ty = try sema.resolveTypeOrPoison(block, operand_src, extra.operand) orelse return .generic_poison_type;
const float_ty = raw_ty.optEuBaseType(zcu);

switch (float_ty.scalarType(zcu).zigTypeTag(zcu)) {
.float, .comptime_float => {},
else => return sema.fail(
block,
operand_src,
"expected vector of floats or float type, found '{f}'",
.{float_ty.fmt(sema.pt)},
),
}

return .fromType(float_ty);
}

fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src: ?LazySrcLoc) !void {
if (block.isComptime()) {
const msg, const fail_block = msg: {
Expand Down
1 change: 1 addition & 0 deletions src/print_zir.zig
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ const Writer = struct {
.work_group_size,
.work_group_id,
.branch_hint,
.float_op_result_ty,
=> {
const inst_data = self.code.extraData(Zir.Inst.UnNode, extended.operand).data;
try self.writeInstRef(stream, inst_data.operand);
Expand Down
28 changes: 28 additions & 0 deletions test/behavior/floatop.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1737,3 +1737,31 @@ test "comptime calls are only memoized when float arguments are bit-for-bit equa
try comptime testMemoization();
try comptime testVectorMemoization(@Vector(4, f32));
}

test "result location forwarded through unary float builtins" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;

const S = struct {
var x: u32 = 10;
};

var y: f64 = 0.0;
y = @sqrt(@floatFromInt(S.x));
y = @sin(@floatFromInt(S.x));
y = @cos(@floatFromInt(S.x));
y = @tan(@floatFromInt(S.x));
y = @exp(@floatFromInt(S.x));
y = @exp2(@floatFromInt(S.x));
y = @log(@floatFromInt(S.x));
y = @log2(@floatFromInt(S.x));
y = @log10(@floatFromInt(S.x));
y = @floor(@floatFromInt(S.x));
y = @ceil(@floatFromInt(S.x));
y = @trunc(@floatFromInt(S.x));
y = @round(@floatFromInt(S.x));
}