Skip to content

Commit db2e8c4

Browse files
authored
Implement for for signed integers (#15)
* implement `checked_binop` * support `panic_nounwind` * bless `for_range_signed` * misc cleanups
1 parent 1103fcc commit db2e8c4

File tree

8 files changed

+86
-113
lines changed

8 files changed

+86
-113
lines changed

crates/rustc_codegen_spirv/src/builder/builder_methods.rs

+73-20
Original file line numberDiff line numberDiff line change
@@ -1318,28 +1318,80 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
13181318
fn checked_binop(
13191319
&mut self,
13201320
oop: OverflowOp,
1321-
_ty: Ty<'_>,
1321+
ty: Ty<'_>,
13221322
lhs: Self::Value,
13231323
rhs: Self::Value,
13241324
) -> (Self::Value, Self::Value) {
1325-
// NOTE(eddyb) this needs to be `undef`, not `false`/`true`, because
1326-
// we don't want the user's boolean constants to keep the zombie alive.
1327-
let bool = SpirvType::Bool.def(self.span(), self);
1328-
let overflowed = self.undef(bool);
1329-
let result = match oop {
1330-
OverflowOp::Add => (self.add(lhs, rhs), overflowed),
1331-
OverflowOp::Sub => (self.sub(lhs, rhs), overflowed),
1332-
OverflowOp::Mul => (self.mul(lhs, rhs), overflowed),
1325+
// adopted partially from https://github.com/ziglang/zig/blob/master/src/codegen/spirv.zig
1326+
let is_add = match oop {
1327+
OverflowOp::Add => true,
1328+
OverflowOp::Sub => false,
1329+
OverflowOp::Mul => {
1330+
// NOTE(eddyb) this needs to be `undef`, not `false`/`true`, because
1331+
// we don't want the user's boolean constants to keep the zombie alive.
1332+
let bool = SpirvType::Bool.def(self.span(), self);
1333+
let overflowed = self.undef(bool);
1334+
1335+
let result = (self.mul(lhs, rhs), overflowed);
1336+
self.zombie(result.1.def(self), "checked mul is not supported yet");
1337+
return result;
1338+
}
13331339
};
1334-
self.zombie(
1335-
result.1.def(self),
1336-
match oop {
1337-
OverflowOp::Add => "checked add is not supported yet",
1338-
OverflowOp::Sub => "checked sub is not supported yet",
1339-
OverflowOp::Mul => "checked mul is not supported yet",
1340-
},
1341-
);
1342-
result
1340+
let signed = match ty.kind() {
1341+
ty::Int(_) => true,
1342+
ty::Uint(_) => false,
1343+
other => self.fatal(format!(
1344+
"Unexpected {} type: {other:#?}",
1345+
match oop {
1346+
OverflowOp::Add => "checked add",
1347+
OverflowOp::Sub => "checked sub",
1348+
OverflowOp::Mul => "checked mul",
1349+
}
1350+
)),
1351+
};
1352+
1353+
let result = if is_add {
1354+
self.add(lhs, rhs)
1355+
} else {
1356+
self.sub(lhs, rhs)
1357+
};
1358+
1359+
let overflowed = if signed {
1360+
// when adding, overflow could happen if
1361+
// - rhs is positive and result < lhs; or
1362+
// - rhs is negative and result > lhs
1363+
// this is equivalent to (rhs < 0) == (result > lhs)
1364+
//
1365+
// when subtracting, overflow happens if
1366+
// - rhs is positive and result > lhs; or
1367+
// - rhs is negative and result < lhs
1368+
// this is equivalent to (rhs < 0) == (result < lhs)
1369+
let rhs_lt_zero = self.icmp(IntPredicate::IntSLT, rhs, self.constant_int(rhs.ty, 0));
1370+
let result_gt_lhs = self.icmp(
1371+
if is_add {
1372+
IntPredicate::IntSGT
1373+
} else {
1374+
IntPredicate::IntSLT
1375+
},
1376+
result,
1377+
lhs,
1378+
);
1379+
self.icmp(IntPredicate::IntEQ, rhs_lt_zero, result_gt_lhs)
1380+
} else {
1381+
// for unsigned addition, overflow occured if the result is less than any of the operands.
1382+
// for subtraction, overflow occured if the result is greater.
1383+
self.icmp(
1384+
if is_add {
1385+
IntPredicate::IntULT
1386+
} else {
1387+
IntPredicate::IntUGT
1388+
},
1389+
result,
1390+
lhs,
1391+
)
1392+
};
1393+
1394+
(result, overflowed)
13431395
}
13441396

13451397
// rustc has the concept of an immediate vs. memory type - bools are compiled to LLVM bools as
@@ -2766,8 +2818,9 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
27662818
kind: SpirvValueKind::Def(b_id),
27672819
..
27682820
},
2769-
_, // `&'static panic::Location<'static>`
2770-
] = args[..]
2821+
// NOTE(fee1-dead): the standard `panic` takes in a `Location` due to `track_caller`.
2822+
// but for `panic_nounwind` it does not, therefore we only look at the first two arguments.
2823+
] = args[..2]
27712824
{
27722825
if let Some(const_msg) = const_str_as_utf8(&[a_id, b_id]) {
27732826
decoded_format_args.const_pieces = Some([const_msg].into_iter().collect());

crates/rustc_codegen_spirv/src/builder/intrinsics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
122122

123123
sym::saturating_add => {
124124
assert_eq!(arg_tys[0], arg_tys[1]);
125-
let result = match &arg_tys[0].kind() {
125+
let result = match arg_tys[0].kind() {
126126
TyKind::Int(_) | TyKind::Uint(_) => {
127127
self.add(args[0].immediate(), args[1].immediate())
128128
}

crates/rustc_codegen_spirv/src/codegen_cx/constant.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ impl<'tcx> CodegenCx<'tcx> {
437437
// println!(
438438
// "Creating const alloc of type {} with {} bytes",
439439
// self.debug_type(ty),
440-
// alloc.len()
440+
// alloc.inner().len()
441441
// );
442442
let mut offset = Size::ZERO;
443443
let result = self.read_from_const_alloc(alloc, &mut offset, ty);

crates/rustc_codegen_spirv/src/codegen_cx/declare.rs

+1
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ impl<'tcx> CodegenCx<'tcx> {
181181
if [
182182
self.tcx.lang_items().panic_fn(),
183183
self.tcx.lang_items().panic_fmt(),
184+
self.tcx.lang_items().panic_nounwind(),
184185
]
185186
.contains(&Some(def_id))
186187
{

tests/README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ whether it should succeed compilation, or fail. If it is expected to fail, there
99
The `src` folder here is the tool that iterates over every file in the `ui` folder. It uses the
1010
`compiletests` library, taken from rustc's own compiletest framework.
1111

12-
You can run compiletests via `cargo compiletests`. This is an alias set up in `.cargo/config` for
12+
You can run compiletests via `cargo compiletest`. This is an alias set up in `.cargo/config` for
1313
`cargo run --release -p compiletests --`. You can filter to run specific tests by passing the
14-
(partial) filenames to `cargo compiletests some_file_name`, and update the `.stderr` files to
14+
(partial) filenames to `cargo compiletest some_file_name`, and update the `.stderr` files to
1515
contain new output via the `--bless` flag (with `--bless`, make sure you're actually supposed to be
1616
changing the .stderr files due to an intentional change, and hand-validate the output is correct
1717
afterwards).

tests/ui/lang/control_flow/for_range_signed-broken.rs

-13
This file was deleted.

tests/ui/lang/control_flow/for_range_signed-broken.stderr

-76
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// build-pass
2+
3+
use spirv_std::spirv;
4+
5+
#[spirv(fragment)]
6+
pub fn main(#[spirv(flat)] i: i32) {
7+
for _ in 0..i {}
8+
}

0 commit comments

Comments
 (0)