about summary refs log tree commit diff
path: root/compiler/rustc_target/src/callconv/csky.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_target/src/callconv/csky.rs')
-rw-r--r--compiler/rustc_target/src/callconv/csky.rs61
1 files changed, 61 insertions, 0 deletions
diff --git a/compiler/rustc_target/src/callconv/csky.rs b/compiler/rustc_target/src/callconv/csky.rs
new file mode 100644
index 00000000000..b1c1ae814a7
--- /dev/null
+++ b/compiler/rustc_target/src/callconv/csky.rs
@@ -0,0 +1,61 @@
+// Reference: CSKY ABI Manual
+// https://occ-oss-prod.oss-cn-hangzhou.aliyuncs.com/resource//1695027452256/T-HEAD_800_Series_ABI_Standards_Manual.pdf
+//
+// Reference: Clang CSKY lowering code
+// https://github.com/llvm/llvm-project/blob/4a074f32a6914f2a8d7215d78758c24942dddc3d/clang/lib/CodeGen/Targets/CSKY.cpp#L76-L162
+
+use crate::abi::call::{ArgAbi, FnAbi, Reg, Uniform};
+
+fn classify_ret<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+    if !arg.layout.is_sized() {
+        // Not touching this...
+        return;
+    }
+    // For return type, aggregate which <= 2*XLen will be returned in registers.
+    // Otherwise, aggregate will be returned indirectly.
+    if arg.layout.is_aggregate() {
+        let total = arg.layout.size;
+        if total.bits() > 64 {
+            arg.make_indirect();
+        } else if total.bits() > 32 {
+            arg.cast_to(Uniform::new(Reg::i32(), total));
+        } else {
+            arg.cast_to(Reg::i32());
+        }
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+}
+
+fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) {
+    if !arg.layout.is_sized() {
+        // Not touching this...
+        return;
+    }
+    // For argument type, the first 4*XLen parts of aggregate will be passed
+    // in registers, and the rest will be passed in stack.
+    // So we can coerce to integers directly and let backend handle it correctly.
+    if arg.layout.is_aggregate() {
+        let total = arg.layout.size;
+        if total.bits() > 32 {
+            arg.cast_to(Uniform::new(Reg::i32(), total));
+        } else {
+            arg.cast_to(Reg::i32());
+        }
+    } else {
+        arg.extend_integer_width_to(32);
+    }
+}
+
+pub(crate) fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) {
+    if !fn_abi.ret.is_ignore() {
+        classify_ret(&mut fn_abi.ret);
+    }
+
+    for arg in fn_abi.args.iter_mut() {
+        if arg.is_ignore() {
+            continue;
+        }
+        classify_arg(arg);
+    }
+}