aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-09-21 22:33:00 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-09-21 23:21:07 -0700
commitaecebf38acc8835db21eeea7b53e4ee26ec739a8 (patch)
tree132a3982487ae7bb1a0210a4ff2b7cd7a2934855 /src/Sema.zig
parent0e2b9ac7770df07212d4d1cbfb15c3aaed0bef18 (diff)
downloadzig-aecebf38acc8835db21eeea7b53e4ee26ec739a8.tar.gz
zig-aecebf38acc8835db21eeea7b53e4ee26ec739a8.zip
stage2: progress towards ability to compile compiler-rt
* prepare compiler-rt to support being compiled by stage2 - put in a few minor workarounds that will be removed later, such as using `builtin.stage2_arch` rather than `builtin.cpu.arch`. - only try to export a few symbols for now - we'll move more symbols over to the "working in stage2" section as they become functional and gain test coverage. - use `inline fn` at function declarations rather than `@call` with an always_inline modifier at the callsites, to avoid depending on the anonymous array literal syntax language feature (for now). * AIR: replace floatcast instruction with fptrunc and fpext for shortening and widening floating point values, respectively. * Introduce a new ZIR instruction, `export_value`, which implements `@export` for the case when the thing to be exported is a local comptime value that points to a function. - AstGen: fix `@export` not properly reporting ambiguous decl references. * Sema: handle ExportOptions linkage. The value is now available to all backends. - Implement setting global linkage as appropriate in the LLVM backend. I did not yet inspect the LLVM IR, so this still needs to be audited. There is already a pending task to make sure the alias stuff is working as intended, and this is related. - Sema almost handles section, just a tiny bit more code is needed in `resolveExportOptions`. * Sema: implement float widening and shortening for both `@floatCast` and float coercion. - Implement the LLVM backend code for this as well.
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig136
1 files changed, 97 insertions, 39 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index 91d12b7b31..a0e3250e56 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -458,6 +458,11 @@ pub fn analyzeBody(
i += 1;
continue;
},
+ .export_value => {
+ try sema.zirExportValue(block, inst);
+ i += 1;
+ continue;
+ },
.set_align_stack => {
try sema.zirSetAlignStack(block, inst);
i += 1;
@@ -2392,30 +2397,33 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErro
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
const src = inst_data.src();
- const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
- const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+ const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const decl_name = sema.code.nullTerminatedString(extra.decl_name);
if (extra.namespace != .none) {
return sema.mod.fail(&block.base, src, "TODO: implement exporting with field access", .{});
}
- const decl = try sema.lookupIdentifier(block, lhs_src, decl_name);
- const options = try sema.resolveInstConst(block, rhs_src, extra.options);
- const struct_obj = options.ty.castTag(.@"struct").?.data;
- const fields = options.val.castTag(.@"struct").?.data[0..struct_obj.fields.count()];
- const name_index = struct_obj.fields.getIndex("name").?;
- const linkage_index = struct_obj.fields.getIndex("linkage").?;
- const section_index = struct_obj.fields.getIndex("section").?;
- const export_name = try fields[name_index].toAllocatedBytes(sema.arena);
- const linkage = fields[linkage_index].toEnum(std.builtin.GlobalLinkage);
+ const decl = try sema.lookupIdentifier(block, operand_src, decl_name);
+ const options = try sema.resolveExportOptions(block, options_src, extra.options);
+ try sema.mod.analyzeExport(&block.base, src, options, decl);
+}
- if (linkage != .Strong) {
- return sema.mod.fail(&block.base, src, "TODO: implement exporting with non-strong linkage", .{});
- }
- if (!fields[section_index].isNull()) {
- return sema.mod.fail(&block.base, src, "TODO: implement exporting with linksection", .{});
- }
+fn zirExportValue(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void {
+ const tracy = trace(@src());
+ defer tracy.end();
- try sema.mod.analyzeExport(&block.base, src, export_name, decl);
+ const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data;
+ const src = inst_data.src();
+ const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
+ const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
+ const operand = try sema.resolveInstConst(block, operand_src, extra.operand);
+ const options = try sema.resolveExportOptions(block, options_src, extra.options);
+ const decl = switch (operand.val.tag()) {
+ .function => operand.val.castTag(.function).?.data.owner_decl,
+ else => return sema.mod.fail(&block.base, operand_src, "TODO implement exporting arbitrary Value objects", .{}), // TODO put this Value into an anonymous Decl and then export it.
+ };
+ try sema.mod.analyzeExport(&block.base, src, options, decl);
}
fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!void {
@@ -4516,11 +4524,18 @@ fn zirFloatCast(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileE
if (try sema.isComptimeKnown(block, operand_src, operand)) {
return sema.coerce(block, dest_type, operand, operand_src);
- } else if (dest_is_comptime_float) {
+ }
+ if (dest_is_comptime_float) {
return sema.mod.fail(&block.base, src, "unable to cast runtime value to 'comptime_float'", .{});
}
-
- return sema.mod.fail(&block.base, src, "TODO implement analyze widen or shorten float", .{});
+ const target = sema.mod.getTarget();
+ const src_bits = operand_ty.floatBits(target);
+ const dst_bits = dest_type.floatBits(target);
+ if (dst_bits >= src_bits) {
+ return sema.coerce(block, dest_type, operand, operand_src);
+ }
+ try sema.requireRuntimeBlock(block, operand_src);
+ return block.addTyOp(.fptrunc, dest_type, operand);
}
fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -7936,6 +7951,31 @@ fn checkAtomicOperandType(
}
}
+fn resolveExportOptions(
+ sema: *Sema,
+ block: *Scope.Block,
+ src: LazySrcLoc,
+ zir_ref: Zir.Inst.Ref,
+) CompileError!std.builtin.ExportOptions {
+ const export_options_ty = try sema.getBuiltinType(block, src, "ExportOptions");
+ const air_ref = sema.resolveInst(zir_ref);
+ const coerced = try sema.coerce(block, export_options_ty, air_ref, src);
+ const val = try sema.resolveConstValue(block, src, coerced);
+ const fields = val.castTag(.@"struct").?.data;
+ const struct_obj = export_options_ty.castTag(.@"struct").?.data;
+ const name_index = struct_obj.fields.getIndex("name").?;
+ const linkage_index = struct_obj.fields.getIndex("linkage").?;
+ const section_index = struct_obj.fields.getIndex("section").?;
+ if (!fields[section_index].isNull()) {
+ return sema.mod.fail(&block.base, src, "TODO: implement exporting with linksection", .{});
+ }
+ return std.builtin.ExportOptions{
+ .name = try fields[name_index].toAllocatedBytes(sema.arena),
+ .linkage = fields[linkage_index].toEnum(std.builtin.GlobalLinkage),
+ .section = null, // TODO
+ };
+}
+
fn resolveAtomicOrder(
sema: *Sema,
block: *Scope.Block,
@@ -9581,7 +9621,7 @@ fn coerce(
const dst_bits = dest_type.floatBits(target);
if (dst_bits >= src_bits) {
try sema.requireRuntimeBlock(block, inst_src);
- return block.addTyOp(.floatcast, dest_type, inst);
+ return block.addTyOp(.fpext, dest_type, inst);
}
}
},
@@ -9729,35 +9769,53 @@ fn coerceNum(
const target = sema.mod.getTarget();
switch (dst_zig_tag) {
- .ComptimeInt, .Int => {
- if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
+ .ComptimeInt, .Int => switch (src_zig_tag) {
+ .Float, .ComptimeFloat => {
if (val.floatHasFraction()) {
- return sema.mod.fail(&block.base, inst_src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst_ty });
+ return sema.mod.fail(&block.base, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val, dest_type });
}
return sema.mod.fail(&block.base, inst_src, "TODO float to int", .{});
- } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
+ },
+ .Int, .ComptimeInt => {
if (!val.intFitsInType(dest_type, target)) {
return sema.mod.fail(&block.base, inst_src, "type {} cannot represent integer value {}", .{ dest_type, val });
}
return try sema.addConstant(dest_type, val);
- }
+ },
+ else => {},
},
- .ComptimeFloat, .Float => {
- if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
- const res = val.floatCast(sema.arena, dest_type) catch |err| switch (err) {
- error.Overflow => return sema.mod.fail(
+ .ComptimeFloat, .Float => switch (src_zig_tag) {
+ .ComptimeFloat => {
+ const result_val = try val.floatCast(sema.arena, dest_type);
+ return try sema.addConstant(dest_type, result_val);
+ },
+ .Float => {
+ const result_val = try val.floatCast(sema.arena, dest_type);
+ if (!val.eql(result_val, dest_type)) {
+ return sema.mod.fail(
&block.base,
inst_src,
- "cast of value {} to type '{}' loses information",
- .{ val, dest_type },
- ),
- error.OutOfMemory => return error.OutOfMemory,
- };
- return try sema.addConstant(dest_type, res);
- } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
+ "type {} cannot represent float value {}",
+ .{ dest_type, val },
+ );
+ }
+ return try sema.addConstant(dest_type, result_val);
+ },
+ .Int, .ComptimeInt => {
const result_val = try val.intToFloat(sema.arena, dest_type, target);
+ // TODO implement this compile error
+ //const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
+ //if (!int_again_val.eql(val, inst_ty)) {
+ // return sema.mod.fail(
+ // &block.base,
+ // inst_src,
+ // "type {} cannot represent integer value {}",
+ // .{ dest_type, val },
+ // );
+ //}
return try sema.addConstant(dest_type, result_val);
- }
+ },
+ else => {},
},
else => {},
}