@@ -846,15 +846,15 @@ pub fn genBody(o: *Object, body: ir.Body) error{ AnalysisFail, OutOfMemory }!voi
846
846
// TODO use a different strategy for add that communicates to the optimizer
847
847
// that wrapping is UB.
848
848
.add = > try genBinOp (o , inst .castTag (.add ).? , " + " ),
849
- .addwrap = > try genWrapOp (o , .add , inst .castTag (.addwrap ).? ),
849
+ .addwrap = > try genWrapOp (o , inst .castTag (.addwrap ).? , " + " , "addw_" ),
850
850
// TODO use a different strategy for sub that communicates to the optimizer
851
851
// that wrapping is UB.
852
852
.sub = > try genBinOp (o , inst .castTag (.sub ).? , " - " ),
853
- .subwrap = > try genWrapOp (o , .sub , inst .castTag (.subwrap ).? ),
853
+ .subwrap = > try genWrapOp (o , inst .castTag (.subwrap ).? , " - " , "subw_" ),
854
854
// TODO use a different strategy for mul that communicates to the optimizer
855
855
// that wrapping is UB.
856
856
.mul = > try genBinOp (o , inst .castTag (.sub ).? , " * " ),
857
- .mulwrap = > try genWrapOp (o , .mul , inst .castTag (.mulwrap ).? ),
857
+ .mulwrap = > try genWrapOp (o , inst .castTag (.mulwrap ).? , " * " , "mulw_" ),
858
858
// TODO use a different strategy for div that communicates to the optimizer
859
859
// that wrapping is UB.
860
860
.div = > try genBinOp (o , inst .castTag (.div ).? , " / " ),
@@ -1039,44 +1039,44 @@ fn genStore(o: *Object, inst: *Inst.BinOp) !CValue {
1039
1039
return CValue .none ;
1040
1040
}
1041
1041
1042
- const WrappingOp = enum {
1043
- add ,
1044
- sub ,
1045
- mul ,
1046
- };
1047
-
1048
- fn genWrapOp (o : * Object , op : WrappingOp , inst : * Inst.BinOp ) ! CValue {
1042
+ fn genWrapOp (o : * Object , inst : * Inst.BinOp , str_op : [* :0 ]const u8 , fn_op : [* :0 ]const u8 ) ! CValue {
1049
1043
if (inst .base .isUnused ())
1050
1044
return CValue .none ;
1051
1045
1052
- const is_signed = inst .base .ty .isSignedInt ();
1046
+ const int_info = inst .base .ty .intInfo (o .dg .module .getTarget ());
1047
+ const bits = int_info .bits ;
1053
1048
1054
1049
// if it's an unsigned int with non-arbitrary bit size then we can just add
1055
- if (! is_signed and inst .base .ty .tag () != .int_unsigned ) {
1056
- return try genBinOp (o , inst , switch (op ) {
1057
- .add = > " + " ,
1058
- .sub = > " - " ,
1059
- .mul = > " * " ,
1060
- });
1050
+ if (int_info .signedness == .unsigned ) {
1051
+ const ok_bits = switch (bits ) {
1052
+ 8 , 16 , 32 , 64 , 128 = > true ,
1053
+ else = > false ,
1054
+ };
1055
+ if (ok_bits or inst .base .ty .tag () != .int_unsigned ) {
1056
+ return try genBinOp (o , inst , str_op );
1057
+ }
1058
+ }
1059
+
1060
+ if (bits > 64 ) {
1061
+ return o .dg .fail (.{ .node_offset = 0 }, "TODO: C backend: genWrapOp for large integers" , .{});
1061
1062
}
1062
1063
1063
1064
var min_buf : [80 ]u8 = undefined ;
1064
- const min = if (! is_signed )
1065
- "0"
1066
- else switch (inst .base .ty .tag ()) {
1067
- .c_short = > "SHRT_MIN" ,
1068
- .c_int = > "INT_MIN" ,
1069
- .c_long = > "LONG_MIN" ,
1070
- .c_longlong = > "LLONG_MIN" ,
1071
- .isize = > "INTPTR_MIN" ,
1072
- else = > blk : {
1073
- // should be able to use undefined here since all the target specifics are handled
1074
- const bits = inst .base .ty .intInfo (@as (std .Target , undefined )).bits ;
1075
- assert (bits <= 64 ); // TODO: large integers
1076
- const val = -1 * std .math .pow (i64 , 2 , @intCast (i64 , bits - 1 ));
1077
- break :blk std .fmt .bufPrint (& min_buf , "{}" , .{val }) catch | e |
1078
- // doesn't fit in some upwards error set, but should never happen
1079
- return if (e == error .NoSpaceLeft ) unreachable else e ;
1065
+ const min = switch (int_info .signedness ) {
1066
+ .unsigned = > "0" ,
1067
+ else = > switch (inst .base .ty .tag ()) {
1068
+ .c_short = > "SHRT_MIN" ,
1069
+ .c_int = > "INT_MIN" ,
1070
+ .c_long = > "LONG_MIN" ,
1071
+ .c_longlong = > "LLONG_MIN" ,
1072
+ .isize = > "INTPTR_MIN" ,
1073
+ else = > blk : {
1074
+ const val = -1 * std .math .pow (i64 , 2 , @intCast (i64 , bits - 1 ));
1075
+ break :blk std .fmt .bufPrint (& min_buf , "{d}" , .{val }) catch | err | switch (err ) {
1076
+ error .NoSpaceLeft = > unreachable ,
1077
+ else = > | e | return e ,
1078
+ };
1079
+ },
1080
1080
},
1081
1081
};
1082
1082
@@ -1093,13 +1093,15 @@ fn genWrapOp(o: *Object, op: WrappingOp, inst: *Inst.BinOp) !CValue {
1093
1093
.isize = > "INTPTR_MAX" ,
1094
1094
.usize = > "UINTPTR_MAX" ,
1095
1095
else = > blk : {
1096
- // should be able to use undefined here since all the target specifics are handled
1097
- const bits = inst .base .ty .intInfo (@as (std .Target , undefined )).bits ;
1098
- assert (bits <= 64 ); // TODO: large integers
1099
- const val = std .math .pow (u64 , 2 , if (is_signed ) (bits - 1 ) else bits ) - 1 ;
1100
- break :blk std .fmt .bufPrint (& max_buf , "{}" , .{val }) catch | e |
1101
- // doesn't fit in some upwards error set, but should never happen
1102
- return if (e == error .NoSpaceLeft ) unreachable else e ;
1096
+ const pow_bits = switch (int_info .signedness ) {
1097
+ .signed = > bits - 1 ,
1098
+ .unsigned = > bits ,
1099
+ };
1100
+ const val = std .math .pow (u64 , 2 , pow_bits ) - 1 ;
1101
+ break :blk std .fmt .bufPrint (& max_buf , "{}" , .{val }) catch | err | switch (err ) {
1102
+ error .NoSpaceLeft = > unreachable ,
1103
+ else = > | e | return e ,
1104
+ };
1103
1105
},
1104
1106
};
1105
1107
@@ -1108,53 +1110,36 @@ fn genWrapOp(o: *Object, op: WrappingOp, inst: *Inst.BinOp) !CValue {
1108
1110
const w = o .writer ();
1109
1111
1110
1112
const ret = try o .allocLocal (inst .base .ty , .Mut );
1111
- try w .writeAll (" = zig_" );
1112
- try w .writeAll (switch (op ) {
1113
- .add = > "addw_" ,
1114
- .sub = > "subw_" ,
1115
- .mul = > return o .dg .fail (.{ .node_offset = 0 }, "TODO: C backend: implement wrapping multiplication operator" , .{}),
1116
- });
1113
+ try w .print (" = zig_{s}" , .{fn_op });
1117
1114
1118
1115
switch (inst .base .ty .tag ()) {
1119
- .u8 = > try w .writeAll ("u8" ),
1120
- .i8 = > try w .writeAll ("i8" ),
1121
- .u16 = > try w .writeAll ("u16" ),
1122
- .i16 = > try w .writeAll ("i16" ),
1123
- .u32 = > try w .writeAll ("u32" ),
1124
- .i32 = > try w .writeAll ("i32" ),
1125
- .u64 = > try w .writeAll ("u64" ),
1126
- .i64 = > try w .writeAll ("i64" ),
1127
1116
.isize = > try w .writeAll ("isize" ),
1128
1117
.c_short = > try w .writeAll ("short" ),
1129
1118
.c_int = > try w .writeAll ("int" ),
1130
1119
.c_long = > try w .writeAll ("long" ),
1131
1120
.c_longlong = > try w .writeAll ("longlong" ),
1132
- .int_signed , .int_unsigned = > {
1133
- if (is_signed ) {
1134
- try w .writeByte ('i' );
1135
- } else {
1136
- try w .writeByte ('u' );
1137
- }
1138
-
1139
- const info_bits = inst .base .ty .intInfo (@as (std .Target , undefined )).bits ;
1140
- inline for (.{ 8 , 16 , 32 , 64 }) | nbits | {
1141
- if (info_bits <= nbits ) {
1142
- try w .print ("{d}" , .{nbits });
1121
+ else = > {
1122
+ const prefix_byte : u8 = switch (int_info .signedness ) {
1123
+ .signed = > 'i' ,
1124
+ .unsigned = > 'u' ,
1125
+ };
1126
+ for ([_ ]u8 { 8 , 16 , 32 , 64 }) | nbits | {
1127
+ if (bits <= nbits ) {
1128
+ try w .print ("{c}{d}" , .{ prefix_byte , nbits });
1143
1129
break ;
1144
1130
}
1145
1131
} else {
1146
- return o . dg . fail (.{ . node_offset = 0 }, "TODO: C backend: implement integer types larger than 64 bits" , .{}) ;
1132
+ unreachable ;
1147
1133
}
1148
1134
},
1149
- else = > unreachable ,
1150
1135
}
1151
1136
1152
1137
try w .writeByte ('(' );
1153
1138
try o .writeCValue (w , lhs );
1154
1139
try w .writeAll (", " );
1155
1140
try o .writeCValue (w , rhs );
1156
1141
1157
- if (is_signed ) {
1142
+ if (int_info . signedness == .signed ) {
1158
1143
try w .print (", {s}" , .{min });
1159
1144
}
1160
1145
@@ -1164,7 +1149,7 @@ fn genWrapOp(o: *Object, op: WrappingOp, inst: *Inst.BinOp) !CValue {
1164
1149
return ret ;
1165
1150
}
1166
1151
1167
- fn genBinOp (o : * Object , inst : * Inst.BinOp , operator : []const u8 ) ! CValue {
1152
+ fn genBinOp (o : * Object , inst : * Inst.BinOp , operator : [* : 0 ]const u8 ) ! CValue {
1168
1153
if (inst .base .isUnused ())
1169
1154
return CValue .none ;
1170
1155
@@ -1176,7 +1161,7 @@ fn genBinOp(o: *Object, inst: *Inst.BinOp, operator: []const u8) !CValue {
1176
1161
1177
1162
try writer .writeAll (" = " );
1178
1163
try o .writeCValue (writer , lhs );
1179
- try writer .writeAll ( operator );
1164
+ try writer .print ( "{s}" , .{ operator } );
1180
1165
try o .writeCValue (writer , rhs );
1181
1166
try writer .writeAll (";\n " );
1182
1167
0 commit comments