Skip to content

Commit 73c56b6

Browse files
committed
feat: integer cast
1 parent 38b2098 commit 73c56b6

File tree

6 files changed

+246
-130
lines changed

6 files changed

+246
-130
lines changed

crates/rustc_codegen_c/src/builder.rs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
1212
use rustc_target::abi::call::FnAbi;
1313
use rustc_target::spec::{HasTargetSpec, Target};
1414

15+
use crate::c_expr;
1516
use crate::context::{CFunctionBuilder, CodegenCx};
16-
use crate::module::{CExpr, CStmt};
17+
use crate::module::{CDecl, CExpr, CStmt, CType};
1718
use crate::utils::slab::Id;
1819

1920
mod abi;
@@ -127,13 +128,13 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
127128
}
128129

129130
fn ret_void(&mut self) {
130-
let mut fuctions = self.cx.functions.borrow_mut();
131-
fuctions[self.bb].push_stmt(CStmt::Return(None));
131+
let mut functions = self.cx.functions.borrow_mut();
132+
functions[self.bb].push_stmt(CStmt::Return(None));
132133
}
133134

134135
fn ret(&mut self, v: Self::Value) {
135-
let mut fuctions = self.cx.functions.borrow_mut();
136-
fuctions[self.bb].push_stmt(CStmt::Return(Some(Box::new(CExpr::Value(v)))));
136+
let mut functions = self.cx.functions.borrow_mut();
137+
functions[self.bb].push_stmt(CStmt::Return(Some(Box::new(CExpr::Value(v)))));
137138
}
138139

139140
fn br(&mut self, dest: Self::BasicBlock) {
@@ -495,8 +496,48 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
495496
todo!()
496497
}
497498

499+
/// Performs cast between integers, x as ty in Rust.
500+
///
501+
/// If the bit width is different, a truncation or extension is required.
502+
/// The type of extension—sign-extension or zero-extension—depends on the
503+
/// signedness of the source type.
504+
///
505+
/// According to the C17 standard, section "6.3.1.3 Signed and unsigned
506+
/// integers", casting to an unsigned integer behaves the same as in Rust.
507+
/// However, casting to a signed integer is implementation-defined.
508+
///
509+
/// Therefore, a two-step cast is necessary. First, cast to an unsigned
510+
/// integer via explicit conversion. Then, use a helper function to cast the
511+
/// result to a signed integer.
498512
fn intcast(&mut self, val: Self::Value, dest_ty: Self::Type, is_signed: bool) -> Self::Value {
499-
todo!()
513+
let mut functions = self.cx.functions.borrow_mut();
514+
let function = &mut functions[self.bb];
515+
let ret = function.next_value();
516+
517+
let dest = if let CType::Primitive(ty) = dest_ty { ty } else { unreachable!() };
518+
let cast = if !dest.is_signed() {
519+
CExpr::Cast { ty: CType::Primitive(dest), expr: Box::new(CExpr::Value(val)) }
520+
} else {
521+
let cast = CExpr::Cast {
522+
ty: CType::Primitive(dest.to_unsigned()),
523+
expr: Box::new(CExpr::Value(val)),
524+
};
525+
CExpr::Call {
526+
callee: c_expr!("__rust_utos"),
527+
args: vec![
528+
c_expr!(dest.to_unsigned().to_string()),
529+
c_expr!(dest.to_string()),
530+
cast,
531+
c_expr!(dest.max_value()),
532+
],
533+
}
534+
};
535+
function.push_stmt(CStmt::Decl(Box::new(CDecl::Var {
536+
name: ret,
537+
ty: dest_ty,
538+
init: Some(cast),
539+
})));
540+
ret
500541
}
501542

502543
fn pointercast(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value {

crates/rustc_codegen_c/src/builder/abi.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::module::CValue;
99
impl<'tcx> AbiBuilderMethods<'tcx> for Builder<'_, 'tcx> {
1010
fn get_param(&mut self, index: usize) -> Self::Value {
1111
// Params are first n variables in the function
12-
CValue::Var(index)
12+
CValue::Local(index)
1313
}
1414
}
1515

crates/rustc_codegen_c/src/context.rs

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -117,27 +117,21 @@ pub struct CFunctionBuilder {
117117
pub ty: CType,
118118
pub params: Vec<(CType, CValue)>,
119119
pub body: Vec<CStmt>,
120-
pub var_names: FxHashMap<CValue, String>,
120+
121121
var_counter: usize,
122122
}
123123

124124
impl CFunctionBuilder {
125125
pub fn new(name: String, ty: CType, params: Vec<CType>) -> Self {
126126
let params: Vec<_> =
127-
params.into_iter().enumerate().map(|(i, ty)| (ty, CValue::Var(i))).collect();
127+
params.into_iter().enumerate().map(|(i, ty)| (ty, CValue::Local(i))).collect();
128128
let var_counter = params.len();
129129

130-
Self { name, ty, params, body: Vec::new(), var_counter, var_names: FxHashMap::default() }
130+
Self { name, ty, params, body: Vec::new(), var_counter }
131131
}
132132

133133
pub fn build(self) -> CFunction {
134-
CFunction {
135-
name: self.name,
136-
ty: self.ty,
137-
params: self.params,
138-
body: self.body,
139-
var_names: self.var_names,
140-
}
134+
CFunction { name: self.name, ty: self.ty, params: self.params, body: self.body }
141135
}
142136

143137
pub fn decl(&self) -> CDecl {
@@ -149,7 +143,7 @@ impl CFunctionBuilder {
149143
}
150144

151145
pub fn next_value(&mut self) -> CValue {
152-
let val = CValue::Var(self.var_counter);
146+
let val = CValue::Local(self.var_counter);
153147
self.var_counter += 1;
154148
val
155149
}

crates/rustc_codegen_c/src/helper.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/** cast from unsigned to signed
2+
* example: `__rust_utos(uint32_t, int32_t, x, INT32_MAX)`
3+
*/
4+
#define __rust_utos(u, s, v, m) \
5+
((v) <= (m) ? ((s)v) : ((s)((u)(v) - (u)(m) - 1)))

0 commit comments

Comments
 (0)