authorgravatar for liljaanton2001@gmail.comantlilja <liljaanton2001@gmail.com> 2024-02-29 19:59:55+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-04-25 22:58:47-07:00
logc231d94960ec2cecbea0de877f645ba5d439fd13
tree1773cde624c119ea7c476b76c2eaa830b137fd0c
parent3648d7df19642b6902b3f75538a826a322211673

LLVM: Remove deprecated or soon to be deprecated constant expressions


2 files changed, 182 insertions(+), 534 deletions(-)

src/codegen/llvm.zig+153-50
......@@ -3665,6 +3665,124 @@ pub const Object = struct {
36653665 );
36663666 }
36673667
3668 fn lowerValueToInt(o: *Object, llvm_int_ty: Builder.Type, arg_val: InternPool.Index) Error!Builder.Constant {
3669 const mod = o.module;
3670 const ip = &mod.intern_pool;
3671 const target = mod.getTarget();
3672
3673 const val = Value.fromInterned(arg_val);
3674 const val_key = ip.indexToKey(val.toIntern());
3675
3676 if (val.isUndefDeep(mod)) return o.builder.undefConst(llvm_int_ty);
3677
3678 const ty = Type.fromInterned(val_key.typeOf());
3679 switch (val_key) {
3680 .extern_func => |extern_func| {
3681 const fn_decl_index = extern_func.decl;
3682 const function_index = try o.resolveLlvmFunction(fn_decl_index);
3683 const ptr = function_index.ptrConst(&o.builder).global.toConst();
3684 return o.builder.convConst(ptr, llvm_int_ty);
3685 },
3686 .func => |func| {
3687 const fn_decl_index = func.owner_decl;
3688 const function_index = try o.resolveLlvmFunction(fn_decl_index);
3689 const ptr = function_index.ptrConst(&o.builder).global.toConst();
3690 return o.builder.convConst(ptr, llvm_int_ty);
3691 },
3692 .ptr => return o.builder.convConst(try o.lowerPtr(arg_val, 0), llvm_int_ty),
3693 .aggregate => switch (ip.indexToKey(ty.toIntern())) {
3694 .struct_type => {
3695 const struct_type = ip.loadStructType(ty.toIntern());
3696 assert(struct_type.haveLayout(ip));
3697 assert(struct_type.layout == .@"packed");
3698 comptime assert(Type.packed_struct_layout_version == 2);
3699 var running_int = try o.builder.intConst(llvm_int_ty, 0);
3700 var running_bits: u16 = 0;
3701 for (struct_type.field_types.get(ip), 0..) |field_ty, field_index| {
3702 if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;
3703
3704 const shift_rhs = try o.builder.intConst(llvm_int_ty, running_bits);
3705 const field_val = try o.lowerValueToInt(llvm_int_ty, (try val.fieldValue(mod, field_index)).toIntern());
3706 const shifted = try o.builder.binConst(.shl, field_val, shift_rhs);
3707
3708 running_int = try o.builder.binConst(.xor, running_int, shifted);
3709
3710 const ty_bit_size: u16 = @intCast(Type.fromInterned(field_ty).bitSize(mod));
3711 running_bits += ty_bit_size;
3712 }
3713 return running_int;
3714 },
3715 .vector_type => {},
3716 else => unreachable,
3717 },
3718 .un => |un| {
3719 const layout = ty.unionGetLayout(mod);
3720 if (layout.payload_size == 0) return o.lowerValue(un.tag);
3721
3722 const union_obj = mod.typeToUnion(ty).?;
3723 const container_layout = union_obj.getLayout(ip);
3724
3725 assert(container_layout == .@"packed");
3726
3727 var need_unnamed = false;
3728 if (un.tag == .none) {
3729 assert(layout.tag_size == 0);
3730 const union_val = try o.lowerValueToInt(llvm_int_ty, un.val);
3731
3732 need_unnamed = true;
3733 return union_val;
3734 }
3735 const field_index = mod.unionTagFieldIndex(union_obj, Value.fromInterned(un.tag)).?;
3736 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
3737 if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(llvm_int_ty, 0);
3738 return o.lowerValueToInt(llvm_int_ty, un.val);
3739 },
3740 .simple_value => |simple_value| switch (simple_value) {
3741 .false, .true => {},
3742 else => unreachable,
3743 },
3744 .int,
3745 .float,
3746 .enum_tag,
3747 => {},
3748 else => unreachable,
3749 }
3750 const bits = ty.bitSize(mod);
3751 const bytes: usize = @intCast(std.mem.alignForward(u64, bits, 8) / 8);
3752
3753 var stack = std.heap.stackFallback(32, o.gpa);
3754 const allocator = stack.get();
3755
3756 const limbs = try allocator.alloc(
3757 std.math.big.Limb,
3758 std.mem.alignForward(usize, bytes, @sizeOf(std.math.big.Limb)) /
3759 @sizeOf(std.math.big.Limb),
3760 );
3761 defer allocator.free(limbs);
3762 @memset(limbs, 0);
3763
3764 val.writeToPackedMemory(
3765 ty,
3766 mod,
3767 std.mem.sliceAsBytes(limbs)[0..bytes],
3768 0,
3769 ) catch unreachable;
3770
3771 if (builtin.target.cpu.arch.endian() == .little) {
3772 if (target.cpu.arch.endian() == .big)
3773 std.mem.reverse(u8, std.mem.sliceAsBytes(limbs)[0..bytes]);
3774 } else if (target.cpu.arch.endian() == .little) {
3775 for (limbs) |*limb| {
3776 limb.* = std.mem.nativeToLittle(usize, limb.*);
3777 }
3778 }
3779
3780 return o.builder.bigIntConst(llvm_int_ty, .{
3781 .limbs = limbs,
3782 .positive = true,
3783 });
3784 }
3785
36683786 fn lowerValue(o: *Object, arg_val: InternPool.Index) Error!Builder.Constant {
36693787 const mod = o.module;
36703788 const ip = &mod.intern_pool;
......@@ -4022,28 +4140,11 @@ pub const Object = struct {
40224140 const struct_ty = try o.lowerType(ty);
40234141 if (struct_type.layout == .@"packed") {
40244142 comptime assert(Type.packed_struct_layout_version == 2);
4025 var running_int = try o.builder.intConst(struct_ty, 0);
4026 var running_bits: u16 = 0;
4027 for (struct_type.field_types.get(ip), 0..) |field_ty, field_index| {
4028 if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;
4029
4030 const non_int_val =
4031 try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern());
4032 const ty_bit_size: u16 = @intCast(Type.fromInterned(field_ty).bitSize(mod));
4033 const small_int_ty = try o.builder.intType(ty_bit_size);
4034 const small_int_val = try o.builder.castConst(
4035 if (Type.fromInterned(field_ty).isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
4036 non_int_val,
4037 small_int_ty,
4038 );
4039 const shift_rhs = try o.builder.intConst(struct_ty, running_bits);
4040 const extended_int_val =
4041 try o.builder.convConst(.unsigned, small_int_val, struct_ty);
4042 const shifted = try o.builder.binConst(.shl, extended_int_val, shift_rhs);
4043 running_int = try o.builder.binConst(.@"or", running_int, shifted);
4044 running_bits += ty_bit_size;
4045 }
4046 return running_int;
4143
4144 const bits = ty.bitSize(mod);
4145 const llvm_int_ty = try o.builder.intType(@intCast(bits));
4146
4147 return o.lowerValueToInt(llvm_int_ty, arg_val);
40474148 }
40484149 const llvm_len = struct_ty.aggregateLen(&o.builder);
40494150
......@@ -4138,12 +4239,10 @@ pub const Object = struct {
41384239 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
41394240 if (container_layout == .@"packed") {
41404241 if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0);
4141 const small_int_val = try o.builder.castConst(
4142 if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
4143 try o.lowerValue(un.val),
4144 try o.builder.intType(@intCast(field_ty.bitSize(mod))),
4145 );
4146 return o.builder.convConst(.unsigned, small_int_val, union_ty);
4242 const bits = ty.bitSize(mod);
4243 const llvm_int_ty = try o.builder.intType(@intCast(bits));
4244
4245 return o.lowerValueToInt(llvm_int_ty, arg_val);
41474246 }
41484247
41494248 // Sometimes we must make an unnamed struct because LLVM does
......@@ -4171,16 +4270,14 @@ pub const Object = struct {
41714270 );
41724271 } else p: {
41734272 assert(layout.tag_size == 0);
4174 const union_val = try o.lowerValue(un.val);
41754273 if (container_layout == .@"packed") {
4176 const bitcast_val = try o.builder.castConst(
4177 .bitcast,
4178 union_val,
4179 try o.builder.intType(@intCast(ty.bitSize(mod))),
4180 );
4181 return o.builder.convConst(.unsigned, bitcast_val, union_ty);
4274 const bits = ty.bitSize(mod);
4275 const llvm_int_ty = try o.builder.intType(@intCast(bits));
4276
4277 return o.lowerValueToInt(llvm_int_ty, arg_val);
41824278 }
41834279
4280 const union_val = try o.lowerValue(un.val);
41844281 need_unnamed = true;
41854282 break :p union_val;
41864283 };
......@@ -4316,12 +4413,11 @@ pub const Object = struct {
43164413 const llvm_global = (try o.resolveGlobalAnonDecl(decl_val, llvm_addr_space, alignment)).ptrConst(&o.builder).global;
43174414
43184415 const llvm_val = try o.builder.convConst(
4319 .unneeded,
43204416 llvm_global.toConst(),
43214417 try o.builder.ptrType(llvm_addr_space),
43224418 );
43234419
4324 return o.builder.convConst(.unneeded, llvm_val, try o.lowerType(ptr_ty));
4420 return o.builder.convConst(llvm_val, try o.lowerType(ptr_ty));
43254421 }
43264422
43274423 fn lowerDeclRefValue(o: *Object, decl_index: InternPool.DeclIndex) Allocator.Error!Builder.Constant {
......@@ -4359,12 +4455,11 @@ pub const Object = struct {
43594455 (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global;
43604456
43614457 const llvm_val = try o.builder.convConst(
4362 .unneeded,
43634458 llvm_global.toConst(),
43644459 try o.builder.ptrType(toLlvmAddressSpace(decl.@"addrspace", mod.getTarget())),
43654460 );
43664461
4367 return o.builder.convConst(.unneeded, llvm_val, try o.lowerType(ptr_ty));
4462 return o.builder.convConst(llvm_val, try o.lowerType(ptr_ty));
43684463 }
43694464
43704465 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) Allocator.Error!Builder.Constant {
......@@ -4750,7 +4845,6 @@ pub const FuncGen = struct {
47504845 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
47514846 variable_index.setAlignment(ty.abiAlignment(mod).toLlvm(), &o.builder);
47524847 return o.builder.convConst(
4753 .unneeded,
47544848 variable_index.toConst(&o.builder),
47554849 try o.builder.ptrType(toLlvmAddressSpace(.generic, target)),
47564850 );
......@@ -10413,9 +10507,9 @@ pub const FuncGen = struct {
1041310507
1041410508 const anded = if (workaround_explicit_mask and payload_llvm_ty != load_llvm_ty) blk: {
1041510509 // this is rendundant with llvm.trunc. But without it, llvm17 emits invalid code for powerpc.
10416 var mask_val = try o.builder.intConst(payload_llvm_ty, -1);
10417 mask_val = try o.builder.castConst(.zext, mask_val, load_llvm_ty);
10418 break :blk try fg.wip.bin(.@"and", shifted, mask_val.toValue(), "");
10510 const mask_val = try o.builder.intValue(payload_llvm_ty, -1);
10511 const zext_mask_val = try fg.wip.cast(.zext, mask_val, load_llvm_ty, "");
10512 break :blk try fg.wip.bin(.@"and", shifted, zext_mask_val, "");
1041910513 } else shifted;
1042010514
1042110515 return fg.wip.conv(.unneeded, anded, payload_llvm_ty, "");
......@@ -10563,14 +10657,23 @@ pub const FuncGen = struct {
1056310657 else
1056410658 try self.wip.cast(.bitcast, elem, value_bits_type, "");
1056510659
10566 var mask_val = try o.builder.intConst(value_bits_type, -1);
10567 mask_val = try o.builder.castConst(.zext, mask_val, containing_int_ty);
10568 mask_val = try o.builder.binConst(.shl, mask_val, shift_amt);
10569 mask_val =
10570 try o.builder.binConst(.xor, mask_val, try o.builder.intConst(containing_int_ty, -1));
10660 const mask_val = blk: {
10661 const zext = try self.wip.cast(
10662 .zext,
10663 try o.builder.intValue(value_bits_type, -1),
10664 containing_int_ty,
10665 "",
10666 );
10667 const shl = try self.wip.bin(.shl, zext, shift_amt.toValue(), "");
10668 break :blk try self.wip.bin(
10669 .xor,
10670 shl,
10671 try o.builder.intValue(containing_int_ty, -1),
10672 "",
10673 );
10674 };
1057110675
10572 const anded_containing_int =
10573 try self.wip.bin(.@"and", containing_int, mask_val.toValue(), "");
10676 const anded_containing_int = try self.wip.bin(.@"and", containing_int, mask_val, "");
1057410677 const extended_value = try self.wip.cast(.zext, value_bits, containing_int_ty, "");
1057510678 const shifted_value = try self.wip.bin(.shl, extended_value, shift_amt.toValue(), "");
1057610679 const ored_value = try self.wip.bin(.@"or", shifted_value, anded_containing_int, "");
src/codegen/llvm/Builder.zig+29-484
......@@ -5694,7 +5694,7 @@ pub const WipFunction = struct {
56945694 ) Allocator.Error!Value {
56955695 const val_ty = val.typeOfWip(self);
56965696 if (val_ty == ty) return val;
5697 return self.cast(self.builder.convTag(Instruction.Tag, signedness, val_ty, ty), val, ty, name);
5697 return self.cast(self.builder.convTag(signedness, val_ty, ty), val, ty, name);
56985698 }
56995699
57005700 pub fn cast(
......@@ -6891,39 +6891,19 @@ pub const Constant = enum(u32) {
68916891 dso_local_equivalent,
68926892 no_cfi,
68936893 trunc,
6894 zext,
6895 sext,
6896 fptrunc,
6897 fpext,
6898 fptoui,
6899 fptosi,
6900 uitofp,
6901 sitofp,
69026894 ptrtoint,
69036895 inttoptr,
69046896 bitcast,
69056897 addrspacecast,
69066898 getelementptr,
69076899 @"getelementptr inbounds",
6908 icmp,
6909 fcmp,
6910 extractelement,
6911 insertelement,
6912 shufflevector,
69136900 add,
69146901 @"add nsw",
69156902 @"add nuw",
69166903 sub,
69176904 @"sub nsw",
69186905 @"sub nuw",
6919 mul,
6920 @"mul nsw",
6921 @"mul nuw",
69226906 shl,
6923 lshr,
6924 ashr,
6925 @"and",
6926 @"or",
69276907 xor,
69286908 @"asm",
69296909 @"asm sideeffect",
......@@ -6952,15 +6932,7 @@ pub const Constant = enum(u32) {
69526932 .@"sub nsw",
69536933 .@"sub nuw",
69546934 => .sub,
6955 .mul,
6956 .@"mul nsw",
6957 .@"mul nuw",
6958 => .mul,
69596935 .shl => .shl,
6960 .lshr => .lshr,
6961 .ashr => .ashr,
6962 .@"and" => .@"and",
6963 .@"or" => .@"or",
69646936 .xor => .xor,
69656937 else => unreachable,
69666938 };
......@@ -6969,14 +6941,6 @@ pub const Constant = enum(u32) {
69696941 pub fn toCastOpcode(self: Tag) CastOpcode {
69706942 return switch (self) {
69716943 .trunc => .trunc,
6972 .zext => .zext,
6973 .sext => .sext,
6974 .fptoui => .fptoui,
6975 .fptosi => .fptosi,
6976 .uitofp => .uitofp,
6977 .sitofp => .sitofp,
6978 .fptrunc => .fptrunc,
6979 .fpext => .fpext,
69806944 .ptrtoint => .ptrtoint,
69816945 .inttoptr => .inttoptr,
69826946 .bitcast => .bitcast,
......@@ -7051,29 +7015,6 @@ pub const Constant = enum(u32) {
70517015 pub const Info = packed struct(u32) { indices_len: u16, inrange: InRangeIndex };
70527016 };
70537017
7054 pub const Compare = extern struct {
7055 cond: u32,
7056 lhs: Constant,
7057 rhs: Constant,
7058 };
7059
7060 pub const ExtractElement = extern struct {
7061 val: Constant,
7062 index: Constant,
7063 };
7064
7065 pub const InsertElement = extern struct {
7066 val: Constant,
7067 elem: Constant,
7068 index: Constant,
7069 };
7070
7071 pub const ShuffleVector = extern struct {
7072 lhs: Constant,
7073 rhs: Constant,
7074 mask: Constant,
7075 };
7076
70777018 pub const Binary = extern struct {
70787019 lhs: Constant,
70797020 rhs: Constant,
......@@ -7149,14 +7090,6 @@ pub const Constant = enum(u32) {
71497090 => builder.ptrTypeAssumeCapacity(@as(Function.Index, @enumFromInt(item.data))
71507091 .ptrConst(builder).global.ptrConst(builder).addr_space),
71517092 .trunc,
7152 .zext,
7153 .sext,
7154 .fptrunc,
7155 .fpext,
7156 .fptoui,
7157 .fptosi,
7158 .uitofp,
7159 .sitofp,
71607093 .ptrtoint,
71617094 .inttoptr,
71627095 .bitcast,
......@@ -7176,35 +7109,13 @@ pub const Constant = enum(u32) {
71767109 };
71777110 return base_ty;
71787111 },
7179 .icmp,
7180 .fcmp,
7181 => builder.constantExtraData(Compare, item.data).lhs.typeOf(builder)
7182 .changeScalarAssumeCapacity(.i1, builder),
7183 .extractelement => builder.constantExtraData(ExtractElement, item.data)
7184 .val.typeOf(builder).childType(builder),
7185 .insertelement => builder.constantExtraData(InsertElement, item.data)
7186 .val.typeOf(builder),
7187 .shufflevector => {
7188 const extra = builder.constantExtraData(ShuffleVector, item.data);
7189 return extra.lhs.typeOf(builder).changeLengthAssumeCapacity(
7190 extra.mask.typeOf(builder).vectorLen(builder),
7191 builder,
7192 );
7193 },
71947112 .add,
71957113 .@"add nsw",
71967114 .@"add nuw",
71977115 .sub,
71987116 .@"sub nsw",
71997117 .@"sub nuw",
7200 .mul,
7201 .@"mul nsw",
7202 .@"mul nuw",
72037118 .shl,
7204 .lshr,
7205 .ashr,
7206 .@"and",
7207 .@"or",
72087119 .xor,
72097120 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
72107121 .@"asm",
......@@ -7516,14 +7427,6 @@ pub const Constant = enum(u32) {
75167427 });
75177428 },
75187429 .trunc,
7519 .zext,
7520 .sext,
7521 .fptrunc,
7522 .fpext,
7523 .fptoui,
7524 .fptosi,
7525 .uitofp,
7526 .sitofp,
75277430 .ptrtoint,
75287431 .inttoptr,
75297432 .bitcast,
......@@ -7550,61 +7453,13 @@ pub const Constant = enum(u32) {
75507453 for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)});
75517454 try writer.writeByte(')');
75527455 },
7553 inline .icmp,
7554 .fcmp,
7555 => |tag| {
7556 const extra = data.builder.constantExtraData(Compare, item.data);
7557 try writer.print("{s} {s} ({%}, {%})", .{
7558 @tagName(tag),
7559 @tagName(@as(switch (tag) {
7560 .icmp => IntegerCondition,
7561 .fcmp => FloatCondition,
7562 else => unreachable,
7563 }, @enumFromInt(extra.cond))),
7564 extra.lhs.fmt(data.builder),
7565 extra.rhs.fmt(data.builder),
7566 });
7567 },
7568 .extractelement => |tag| {
7569 const extra = data.builder.constantExtraData(ExtractElement, item.data);
7570 try writer.print("{s} ({%}, {%})", .{
7571 @tagName(tag),
7572 extra.val.fmt(data.builder),
7573 extra.index.fmt(data.builder),
7574 });
7575 },
7576 .insertelement => |tag| {
7577 const extra = data.builder.constantExtraData(InsertElement, item.data);
7578 try writer.print("{s} ({%}, {%}, {%})", .{
7579 @tagName(tag),
7580 extra.val.fmt(data.builder),
7581 extra.elem.fmt(data.builder),
7582 extra.index.fmt(data.builder),
7583 });
7584 },
7585 .shufflevector => |tag| {
7586 const extra = data.builder.constantExtraData(ShuffleVector, item.data);
7587 try writer.print("{s} ({%}, {%}, {%})", .{
7588 @tagName(tag),
7589 extra.lhs.fmt(data.builder),
7590 extra.rhs.fmt(data.builder),
7591 extra.mask.fmt(data.builder),
7592 });
7593 },
75947456 .add,
75957457 .@"add nsw",
75967458 .@"add nuw",
75977459 .sub,
75987460 .@"sub nsw",
75997461 .@"sub nuw",
7600 .mul,
7601 .@"mul nsw",
7602 .@"mul nuw",
76037462 .shl,
7604 .lshr,
7605 .ashr,
7606 .@"and",
7607 .@"or",
76087463 .xor,
76097464 => |tag| {
76107465 const extra = data.builder.constantExtraData(Binary, item.data);
......@@ -9278,21 +9133,19 @@ pub fn noCfiValue(self: *Builder, function: Function.Index) Allocator.Error!Valu
92789133
92799134pub fn convConst(
92809135 self: *Builder,
9281 signedness: Constant.Cast.Signedness,
92829136 val: Constant,
92839137 ty: Type,
92849138) Allocator.Error!Constant {
92859139 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
9286 return self.convConstAssumeCapacity(signedness, val, ty);
9140 return self.convConstAssumeCapacity(val, ty);
92879141}
92889142
92899143pub fn convValue(
92909144 self: *Builder,
9291 signedness: Constant.Cast.Signedness,
92929145 val: Constant,
92939146 ty: Type,
92949147) Allocator.Error!Value {
9295 return (try self.convConst(signedness, val, ty)).toValue();
9148 return (try self.convConst(val, ty)).toValue();
92969149}
92979150
92989151pub fn castConst(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Allocator.Error!Constant {
......@@ -9328,92 +9181,6 @@ pub fn gepValue(
93289181 return (try self.gepConst(kind, ty, base, inrange, indices)).toValue();
93299182}
93309183
9331pub fn icmpConst(
9332 self: *Builder,
9333 cond: IntegerCondition,
9334 lhs: Constant,
9335 rhs: Constant,
9336) Allocator.Error!Constant {
9337 try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0);
9338 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
9339}
9340
9341pub fn icmpValue(
9342 self: *Builder,
9343 cond: IntegerCondition,
9344 lhs: Constant,
9345 rhs: Constant,
9346) Allocator.Error!Value {
9347 return (try self.icmpConst(cond, lhs, rhs)).toValue();
9348}
9349
9350pub fn fcmpConst(
9351 self: *Builder,
9352 cond: FloatCondition,
9353 lhs: Constant,
9354 rhs: Constant,
9355) Allocator.Error!Constant {
9356 try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0);
9357 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
9358}
9359
9360pub fn fcmpValue(
9361 self: *Builder,
9362 cond: FloatCondition,
9363 lhs: Constant,
9364 rhs: Constant,
9365) Allocator.Error!Value {
9366 return (try self.fcmpConst(cond, lhs, rhs)).toValue();
9367}
9368
9369pub fn extractElementConst(self: *Builder, val: Constant, index: Constant) Allocator.Error!Constant {
9370 try self.ensureUnusedConstantCapacity(1, Constant.ExtractElement, 0);
9371 return self.extractElementConstAssumeCapacity(val, index);
9372}
9373
9374pub fn extractElementValue(self: *Builder, val: Constant, index: Constant) Allocator.Error!Value {
9375 return (try self.extractElementConst(val, index)).toValue();
9376}
9377
9378pub fn insertElementConst(
9379 self: *Builder,
9380 val: Constant,
9381 elem: Constant,
9382 index: Constant,
9383) Allocator.Error!Constant {
9384 try self.ensureUnusedConstantCapacity(1, Constant.InsertElement, 0);
9385 return self.insertElementConstAssumeCapacity(val, elem, index);
9386}
9387
9388pub fn insertElementValue(
9389 self: *Builder,
9390 val: Constant,
9391 elem: Constant,
9392 index: Constant,
9393) Allocator.Error!Value {
9394 return (try self.insertElementConst(val, elem, index)).toValue();
9395}
9396
9397pub fn shuffleVectorConst(
9398 self: *Builder,
9399 lhs: Constant,
9400 rhs: Constant,
9401 mask: Constant,
9402) Allocator.Error!Constant {
9403 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
9404 try self.ensureUnusedConstantCapacity(1, Constant.ShuffleVector, 0);
9405 return self.shuffleVectorConstAssumeCapacity(lhs, rhs, mask);
9406}
9407
9408pub fn shuffleVectorValue(
9409 self: *Builder,
9410 lhs: Constant,
9411 rhs: Constant,
9412 mask: Constant,
9413) Allocator.Error!Value {
9414 return (try self.shuffleVectorConst(lhs, rhs, mask)).toValue();
9415}
9416
94179184pub fn binConst(
94189185 self: *Builder,
94199186 tag: Constant.Tag,
......@@ -11390,11 +11157,10 @@ fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
1139011157
1139111158fn convTag(
1139211159 self: *Builder,
11393 comptime Tag: type,
1139411160 signedness: Constant.Cast.Signedness,
1139511161 val_ty: Type,
1139611162 ty: Type,
11397) Tag {
11163) Function.Instruction.Tag {
1139811164 assert(val_ty != ty);
1139911165 return switch (val_ty.scalarTag(self)) {
1140011166 .simple => switch (ty.scalarTag(self)) {
......@@ -11437,15 +11203,38 @@ fn convTag(
1143711203 };
1143811204}
1143911205
11206fn convConstTag(
11207 self: *Builder,
11208 val_ty: Type,
11209 ty: Type,
11210) Constant.Tag {
11211 assert(val_ty != ty);
11212 return switch (val_ty.scalarTag(self)) {
11213 .integer => switch (ty.scalarTag(self)) {
11214 .integer => switch (std.math.order(val_ty.scalarBits(self), ty.scalarBits(self))) {
11215 .gt => .trunc,
11216 else => unreachable,
11217 },
11218 .pointer => .inttoptr,
11219 else => unreachable,
11220 },
11221 .pointer => switch (ty.scalarTag(self)) {
11222 .integer => .ptrtoint,
11223 .pointer => .addrspacecast,
11224 else => unreachable,
11225 },
11226 else => unreachable,
11227 };
11228}
11229
1144011230fn convConstAssumeCapacity(
1144111231 self: *Builder,
11442 signedness: Constant.Cast.Signedness,
1144311232 val: Constant,
1144411233 ty: Type,
1144511234) Constant {
1144611235 const val_ty = val.typeOf(self);
1144711236 if (val_ty == ty) return val;
11448 return self.castConstAssumeCapacity(self.convTag(Constant.Tag, signedness, val_ty, ty), val, ty);
11237 return self.castConstAssumeCapacity(self.convConstTag(val_ty, ty), val, ty);
1144911238}
1145011239
1145111240fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, val: Constant, ty: Type) Constant {
......@@ -11570,179 +11359,6 @@ fn gepConstAssumeCapacity(
1157011359 return @enumFromInt(gop.index);
1157111360}
1157211361
11573fn icmpConstAssumeCapacity(
11574 self: *Builder,
11575 cond: IntegerCondition,
11576 lhs: Constant,
11577 rhs: Constant,
11578) Constant {
11579 const Adapter = struct {
11580 builder: *const Builder,
11581 pub fn hash(_: @This(), key: Constant.Compare) u32 {
11582 return @truncate(std.hash.Wyhash.hash(
11583 std.hash.uint32(@intFromEnum(Constant.tag.icmp)),
11584 std.mem.asBytes(&key),
11585 ));
11586 }
11587 pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool {
11588 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .icmp) return false;
11589 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11590 const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data);
11591 return std.meta.eql(lhs_key, rhs_extra);
11592 }
11593 };
11594 const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs };
11595 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11596 if (!gop.found_existing) {
11597 gop.key_ptr.* = {};
11598 gop.value_ptr.* = {};
11599 self.constant_items.appendAssumeCapacity(.{
11600 .tag = .icmp,
11601 .data = self.addConstantExtraAssumeCapacity(data),
11602 });
11603 }
11604 return @enumFromInt(gop.index);
11605}
11606
11607fn fcmpConstAssumeCapacity(
11608 self: *Builder,
11609 cond: FloatCondition,
11610 lhs: Constant,
11611 rhs: Constant,
11612) Constant {
11613 const Adapter = struct {
11614 builder: *const Builder,
11615 pub fn hash(_: @This(), key: Constant.Compare) u32 {
11616 return @truncate(std.hash.Wyhash.hash(
11617 std.hash.uint32(@intFromEnum(Constant.tag.fcmp)),
11618 std.mem.asBytes(&key),
11619 ));
11620 }
11621 pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool {
11622 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fcmp) return false;
11623 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11624 const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data);
11625 return std.meta.eql(lhs_key, rhs_extra);
11626 }
11627 };
11628 const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs };
11629 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11630 if (!gop.found_existing) {
11631 gop.key_ptr.* = {};
11632 gop.value_ptr.* = {};
11633 self.constant_items.appendAssumeCapacity(.{
11634 .tag = .fcmp,
11635 .data = self.addConstantExtraAssumeCapacity(data),
11636 });
11637 }
11638 return @enumFromInt(gop.index);
11639}
11640
11641fn extractElementConstAssumeCapacity(
11642 self: *Builder,
11643 val: Constant,
11644 index: Constant,
11645) Constant {
11646 const Adapter = struct {
11647 builder: *const Builder,
11648 pub fn hash(_: @This(), key: Constant.ExtractElement) u32 {
11649 return @truncate(std.hash.Wyhash.hash(
11650 comptime std.hash.uint32(@intFromEnum(Constant.Tag.extractelement)),
11651 std.mem.asBytes(&key),
11652 ));
11653 }
11654 pub fn eql(ctx: @This(), lhs_key: Constant.ExtractElement, _: void, rhs_index: usize) bool {
11655 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .extractelement) return false;
11656 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11657 const rhs_extra = ctx.builder.constantExtraData(Constant.ExtractElement, rhs_data);
11658 return std.meta.eql(lhs_key, rhs_extra);
11659 }
11660 };
11661 const data = Constant.ExtractElement{ .val = val, .index = index };
11662 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11663 if (!gop.found_existing) {
11664 gop.key_ptr.* = {};
11665 gop.value_ptr.* = {};
11666 self.constant_items.appendAssumeCapacity(.{
11667 .tag = .extractelement,
11668 .data = self.addConstantExtraAssumeCapacity(data),
11669 });
11670 }
11671 return @enumFromInt(gop.index);
11672}
11673
11674fn insertElementConstAssumeCapacity(
11675 self: *Builder,
11676 val: Constant,
11677 elem: Constant,
11678 index: Constant,
11679) Constant {
11680 const Adapter = struct {
11681 builder: *const Builder,
11682 pub fn hash(_: @This(), key: Constant.InsertElement) u32 {
11683 return @truncate(std.hash.Wyhash.hash(
11684 comptime std.hash.uint32(@intFromEnum(Constant.Tag.insertelement)),
11685 std.mem.asBytes(&key),
11686 ));
11687 }
11688 pub fn eql(ctx: @This(), lhs_key: Constant.InsertElement, _: void, rhs_index: usize) bool {
11689 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .insertelement) return false;
11690 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11691 const rhs_extra = ctx.builder.constantExtraData(Constant.InsertElement, rhs_data);
11692 return std.meta.eql(lhs_key, rhs_extra);
11693 }
11694 };
11695 const data = Constant.InsertElement{ .val = val, .elem = elem, .index = index };
11696 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11697 if (!gop.found_existing) {
11698 gop.key_ptr.* = {};
11699 gop.value_ptr.* = {};
11700 self.constant_items.appendAssumeCapacity(.{
11701 .tag = .insertelement,
11702 .data = self.addConstantExtraAssumeCapacity(data),
11703 });
11704 }
11705 return @enumFromInt(gop.index);
11706}
11707
11708fn shuffleVectorConstAssumeCapacity(
11709 self: *Builder,
11710 lhs: Constant,
11711 rhs: Constant,
11712 mask: Constant,
11713) Constant {
11714 assert(lhs.typeOf(self).isVector(self.builder));
11715 assert(lhs.typeOf(self) == rhs.typeOf(self));
11716 assert(mask.typeOf(self).scalarType(self).isInteger(self));
11717 _ = lhs.typeOf(self).changeLengthAssumeCapacity(mask.typeOf(self).vectorLen(self), self);
11718 const Adapter = struct {
11719 builder: *const Builder,
11720 pub fn hash(_: @This(), key: Constant.ShuffleVector) u32 {
11721 return @truncate(std.hash.Wyhash.hash(
11722 comptime std.hash.uint32(@intFromEnum(Constant.Tag.shufflevector)),
11723 std.mem.asBytes(&key),
11724 ));
11725 }
11726 pub fn eql(ctx: @This(), lhs_key: Constant.ShuffleVector, _: void, rhs_index: usize) bool {
11727 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .shufflevector) return false;
11728 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
11729 const rhs_extra = ctx.builder.constantExtraData(Constant.ShuffleVector, rhs_data);
11730 return std.meta.eql(lhs_key, rhs_extra);
11731 }
11732 };
11733 const data = Constant.ShuffleVector{ .lhs = lhs, .rhs = rhs, .mask = mask };
11734 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
11735 if (!gop.found_existing) {
11736 gop.key_ptr.* = {};
11737 gop.value_ptr.* = {};
11738 self.constant_items.appendAssumeCapacity(.{
11739 .tag = .shufflevector,
11740 .data = self.addConstantExtraAssumeCapacity(data),
11741 });
11742 }
11743 return @enumFromInt(gop.index);
11744}
11745
1174611362fn binConstAssumeCapacity(
1174711363 self: *Builder,
1174811364 tag: Constant.Tag,
......@@ -11756,14 +11372,7 @@ fn binConstAssumeCapacity(
1175611372 .sub,
1175711373 .@"sub nsw",
1175811374 .@"sub nuw",
11759 .mul,
11760 .@"mul nsw",
11761 .@"mul nuw",
1176211375 .shl,
11763 .lshr,
11764 .ashr,
11765 .@"and",
11766 .@"or",
1176711376 .xor,
1176811377 => {},
1176911378 else => unreachable,
......@@ -13938,16 +13547,8 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
1393813547 .bitcast,
1393913548 .inttoptr,
1394013549 .ptrtoint,
13941 .fptosi,
13942 .fptoui,
13943 .sitofp,
13944 .uitofp,
1394513550 .addrspacecast,
13946 .fptrunc,
1394713551 .trunc,
13948 .fpext,
13949 .sext,
13950 .zext,
1395113552 => |tag| {
1395213553 const extra = self.constantExtraData(Constant.Cast, data);
1395313554 try constants_block.writeAbbrevAdapted(Constants.Cast{
......@@ -13962,14 +13563,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
1396213563 .sub,
1396313564 .@"sub nsw",
1396413565 .@"sub nuw",
13965 .mul,
13966 .@"mul nsw",
13967 .@"mul nuw",
1396813566 .shl,
13969 .lshr,
13970 .ashr,
13971 .@"and",
13972 .@"or",
1397313567 .xor,
1397413568 => |tag| {
1397513569 const extra = self.constantExtraData(Constant.Binary, data);
......@@ -13979,55 +13573,6 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
1397913573 .rhs = extra.rhs,
1398013574 }, constant_adapter);
1398113575 },
13982 .icmp,
13983 .fcmp,
13984 => {
13985 const extra = self.constantExtraData(Constant.Compare, data);
13986 try constants_block.writeAbbrevAdapted(Constants.Cmp{
13987 .ty = extra.lhs.typeOf(self),
13988 .lhs = extra.lhs,
13989 .rhs = extra.rhs,
13990 .pred = extra.cond,
13991 }, constant_adapter);
13992 },
13993 .extractelement => {
13994 const extra = self.constantExtraData(Constant.ExtractElement, data);
13995 try constants_block.writeAbbrevAdapted(Constants.ExtractElement{
13996 .val_type = extra.val.typeOf(self),
13997 .val = extra.val,
13998 .index_type = extra.index.typeOf(self),
13999 .index = extra.index,
14000 }, constant_adapter);
14001 },
14002 .insertelement => {
14003 const extra = self.constantExtraData(Constant.InsertElement, data);
14004 try constants_block.writeAbbrevAdapted(Constants.InsertElement{
14005 .val = extra.val,
14006 .elem = extra.elem,
14007 .index_type = extra.index.typeOf(self),
14008 .index = extra.index,
14009 }, constant_adapter);
14010 },
14011 .shufflevector => {
14012 const extra = self.constantExtraData(Constant.ShuffleVector, data);
14013 const ty = constant.typeOf(self);
14014 const lhs_type = extra.lhs.typeOf(self);
14015 // Check if instruction is widening, truncating or not
14016 if (ty == lhs_type) {
14017 try constants_block.writeAbbrevAdapted(Constants.ShuffleVector{
14018 .lhs = extra.lhs,
14019 .rhs = extra.rhs,
14020 .mask = extra.mask,
14021 }, constant_adapter);
14022 } else {
14023 try constants_block.writeAbbrevAdapted(Constants.ShuffleVectorEx{
14024 .ty = ty,
14025 .lhs = extra.lhs,
14026 .rhs = extra.rhs,
14027 .mask = extra.mask,
14028 }, constant_adapter);
14029 }
14030 },
1403113576 .getelementptr,
1403213577 .@"getelementptr inbounds",
1403313578 => |tag| {