Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 66 additions & 20 deletions llvm/src/codegen/abi_c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,16 @@ fn is_float_ty<'ctx>(td: &TargetData, t: BasicTypeEnum<'ctx>) -> Option<u32> {
}
}

fn any_ptr_basic<'ctx>(ty: AnyTypeEnum<'ctx>) -> BasicTypeEnum<'ctx> {
fn any_ptr_basic<'ctx>(context: &'ctx Context, ty: AnyTypeEnum<'ctx>) -> BasicTypeEnum<'ctx> {
let aspace = AddressSpace::default();
match ty {
AnyTypeEnum::ArrayType(t) => t.ptr_type(aspace).as_basic_type_enum(),
AnyTypeEnum::FloatType(t) => t.ptr_type(aspace).as_basic_type_enum(),
AnyTypeEnum::FunctionType(t) => t.ptr_type(aspace).as_basic_type_enum(),
AnyTypeEnum::IntType(t) => t.ptr_type(aspace).as_basic_type_enum(),
AnyTypeEnum::PointerType(t) => t.ptr_type(aspace).as_basic_type_enum(),
AnyTypeEnum::StructType(t) => t.ptr_type(aspace).as_basic_type_enum(),
AnyTypeEnum::VectorType(t) => t.ptr_type(aspace).as_basic_type_enum(),
AnyTypeEnum::ArrayType(_)
| AnyTypeEnum::FloatType(_)
| AnyTypeEnum::FunctionType(_)
| AnyTypeEnum::IntType(_)
| AnyTypeEnum::PointerType(_)
| AnyTypeEnum::StructType(_)
| AnyTypeEnum::VectorType(_) => context.ptr_type(aspace).as_basic_type_enum(),
_ => panic!("unsupported AnyTypeEnum for ptr"),
}
}
Expand Down Expand Up @@ -372,6 +372,24 @@ fn classify_param_arm64_darwin<'ctx>(
ParamLowering::Direct(t)
}

fn classify_param_riscv64<'ctx>(td: &TargetData, t: BasicTypeEnum<'ctx>) -> ParamLowering<'ctx> {
let size = td.get_store_size(&t) as u64;
let is_agg = matches!(
t,
BasicTypeEnum::StructType(_) | BasicTypeEnum::ArrayType(_)
);

if is_agg && size > 16 {
let align = td.get_abi_alignment(&t) as u32;
return ParamLowering::ByVal {
ty: t.as_any_type_enum(),
align,
};
}

ParamLowering::Direct(t)
}

fn classify_ret_arm64_darwin<'ctx>(
td: &TargetData,
t: Option<BasicTypeEnum<'ctx>>,
Expand All @@ -396,19 +414,44 @@ fn classify_ret_arm64_darwin<'ctx>(
RetLowering::Direct(t)
}

fn classify_ret_riscv64<'ctx>(
td: &TargetData,
t: Option<BasicTypeEnum<'ctx>>,
) -> RetLowering<'ctx> {
let Some(t) = t else {
return RetLowering::Void;
};
let size = td.get_store_size(&t) as u64;
let is_agg = matches!(
t,
BasicTypeEnum::StructType(_) | BasicTypeEnum::ArrayType(_)
);

if is_agg && size > 16 {
let align = td.get_abi_alignment(&t) as u32;
return RetLowering::SRet {
ty: t.as_any_type_enum(),
align,
};
}

RetLowering::Direct(t)
}

fn classify_param<'ctx>(
context: &'ctx Context,
td: &TargetData,
target: CodegenTarget,
t: BasicTypeEnum<'ctx>,
) -> ParamLowering<'ctx> {
match target {
CodegenTarget::LinuxX86_64 | CodegenTarget::DarwinX86_64 => {
classify_param_x86_64_sysv(context, td, t)
}
CodegenTarget::LinuxArm64 | CodegenTarget::DarwinArm64 => {
classify_param_arm64_darwin(td, t)
}
CodegenTarget::LinuxX86_64
| CodegenTarget::DarwinX86_64
| CodegenTarget::FreestandingX86_64 => classify_param_x86_64_sysv(context, td, t),
CodegenTarget::LinuxArm64
| CodegenTarget::DarwinArm64
| CodegenTarget::FreestandingArm64 => classify_param_arm64_darwin(td, t),
CodegenTarget::FreestandingRISCV64 => classify_param_riscv64(td, t),
}
}

Expand All @@ -419,10 +462,13 @@ fn classify_ret<'ctx>(
t: Option<BasicTypeEnum<'ctx>>,
) -> RetLowering<'ctx> {
match target {
CodegenTarget::LinuxX86_64 | CodegenTarget::DarwinX86_64 => {
classify_ret_x86_64_sysv(context, td, t)
}
CodegenTarget::LinuxArm64 | CodegenTarget::DarwinArm64 => classify_ret_arm64_darwin(td, t),
CodegenTarget::LinuxX86_64
| CodegenTarget::DarwinX86_64
| CodegenTarget::FreestandingX86_64 => classify_ret_x86_64_sysv(context, td, t),
CodegenTarget::LinuxArm64
| CodegenTarget::DarwinArm64
| CodegenTarget::FreestandingArm64 => classify_ret_arm64_darwin(td, t),
CodegenTarget::FreestandingRISCV64 => classify_ret_riscv64(td, t),
}
}

Expand Down Expand Up @@ -468,7 +514,7 @@ pub fn lower_extern_c<'ctx>(

if let RetLowering::SRet { ty, .. } = &ret {
// sret param is ptr to the return aggregate
let ptr = any_ptr_basic(ty.clone());
let ptr = any_ptr_basic(context, ty.clone());
llvm_param_types.push(ptr.into());
}

Expand All @@ -481,7 +527,7 @@ pub fn lower_extern_c<'ctx>(
}
}
ParamLowering::ByVal { ty, .. } => {
let ptr = any_ptr_basic(ty.clone());
let ptr = any_ptr_basic(context, ty.clone());
llvm_param_types.push(ptr.into());
}
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/src/codegen/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::module::Module;
use inkwell::types::{AsTypeRef, BasicType, BasicTypeEnum, StructType};
use inkwell::values::{BasicValue, IntValue, PointerValue};
use inkwell::values::{IntValue, PointerValue};
use parser::ast::{Expression, Literal, WaveType};

use std::collections::HashMap;
Expand Down
2 changes: 1 addition & 1 deletion llvm/src/codegen/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ fn resolve_ast_node(n: &ASTNode, named: &HashMap<String, WaveType>) -> ASTNode {
ASTNode::ProtoImpl(p) => ASTNode::ProtoImpl(resolve_proto(p, named)),
ASTNode::Variable(v) => ASTNode::Variable(resolve_variable(v, named)),

ASTNode::TypeAlias(_) | ASTNode::Enum(_) => n.clone(),
ASTNode::TypeAlias(_) => n.clone(),

_ => n.clone(),
}
Expand Down
8 changes: 4 additions & 4 deletions llvm/src/codegen/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ pub fn get_llvm_type<'a>(context: &'a Context, ty: &TokenType) -> BasicTypeEnum<
TokenType::TypeChar => context.i8_type().as_basic_type_enum(),
TokenType::TypeByte => context.i8_type().as_basic_type_enum(),
TokenType::TypePointer(inner_type) => {
let inner_llvm_type = get_llvm_type(context, inner_type);
inner_llvm_type
let _inner_llvm_type = get_llvm_type(context, inner_type);
context
.ptr_type(AddressSpace::default())
.as_basic_type_enum()
}
Expand All @@ -47,17 +47,17 @@ pub fn get_llvm_type<'a>(context: &'a Context, ty: &TokenType) -> BasicTypeEnum<
.as_basic_type_enum()
}
TokenType::TypeString => context
.i8_type()
.ptr_type(AddressSpace::default())
.as_basic_type_enum(),
_ => panic!("Unsupported type: {:?}", ty),
}
}

#[allow(dead_code)]
pub unsafe fn create_alloc<'a>(
context: &'a Context,
builder: &'a inkwell::builder::Builder<'a>,
function: FunctionValue<'a>,
_function: FunctionValue<'a>,
name: &'a str,
) -> PointerValue<'a> {
let alloca = builder.build_alloca(context.i32_type(), name).unwrap();
Expand Down
117 changes: 109 additions & 8 deletions llvm/src/codegen/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,21 +126,80 @@ fn reg_phys_group_arm64(token: &str) -> Option<String> {
None
}

fn reg_phys_group_riscv64(token: &str) -> Option<String> {
match token {
"zero" => return Some("x0".to_string()),
"ra" => return Some("x1".to_string()),
"sp" => return Some("x2".to_string()),
"gp" => return Some("x3".to_string()),
"tp" => return Some("x4".to_string()),
"t0" => return Some("x5".to_string()),
"t1" => return Some("x6".to_string()),
"t2" => return Some("x7".to_string()),
"s0" | "fp" => return Some("x8".to_string()),
"s1" => return Some("x9".to_string()),
"a0" => return Some("x10".to_string()),
"a1" => return Some("x11".to_string()),
"a2" => return Some("x12".to_string()),
"a3" => return Some("x13".to_string()),
"a4" => return Some("x14".to_string()),
"a5" => return Some("x15".to_string()),
"a6" => return Some("x16".to_string()),
"a7" => return Some("x17".to_string()),
"s2" => return Some("x18".to_string()),
"s3" => return Some("x19".to_string()),
"s4" => return Some("x20".to_string()),
"s5" => return Some("x21".to_string()),
"s6" => return Some("x22".to_string()),
"s7" => return Some("x23".to_string()),
"s8" => return Some("x24".to_string()),
"s9" => return Some("x25".to_string()),
"s10" => return Some("x26".to_string()),
"s11" => return Some("x27".to_string()),
"t3" => return Some("x28".to_string()),
"t4" => return Some("x29".to_string()),
"t5" => return Some("x30".to_string()),
"t6" => return Some("x31".to_string()),
_ => {}
}

if let Some(num) = token.strip_prefix('x') {
if num.chars().all(|c| c.is_ascii_digit()) && !num.is_empty() {
if let Ok(n) = num.parse::<u32>() {
if n <= 31 {
return Some(format!("x{}", n));
}
}
}
}

None
}

/// Decide whether user token is a real register or a constraint class.
fn parse_token(target: CodegenTarget, raw: &str) -> RegToken {
let raw_norm = normalize_token(raw);
let phys_group = match target {
CodegenTarget::LinuxX86_64 | CodegenTarget::DarwinX86_64 => {
CodegenTarget::LinuxX86_64
| CodegenTarget::DarwinX86_64
| CodegenTarget::FreestandingX86_64 => {
reg_phys_group_x86_64(&raw_norm).map(|s| s.to_string())
}
CodegenTarget::LinuxArm64 | CodegenTarget::DarwinArm64 => reg_phys_group_arm64(&raw_norm),
CodegenTarget::LinuxArm64
| CodegenTarget::DarwinArm64
| CodegenTarget::FreestandingArm64 => reg_phys_group_arm64(&raw_norm),
CodegenTarget::FreestandingRISCV64 => reg_phys_group_riscv64(&raw_norm),
};
RegToken {
raw_norm,
phys_group,
}
}

fn is_valid_constraint_class(token: &str) -> bool {
matches!(token, "r" | "m" | "rm" | "i" | "ri" | "im" | "irm")
}

/// For conservative kernel mode:
/// - ALWAYS clobber memory + flags-ish
/// - If ANY operand uses a *class constraint* (no concrete phys reg),
Expand All @@ -155,15 +214,20 @@ fn build_default_clobbers(
match mode {
AsmSafetyMode::ConservativeKernel => {
let mut clobbers = match target {
CodegenTarget::LinuxX86_64 | CodegenTarget::DarwinX86_64 => vec![
CodegenTarget::LinuxX86_64
| CodegenTarget::DarwinX86_64
| CodegenTarget::FreestandingX86_64 => vec![
"~{memory}".to_string(),
"~{dirflag}".to_string(),
"~{fpsr}".to_string(),
"~{flags}".to_string(),
],
CodegenTarget::LinuxArm64 | CodegenTarget::DarwinArm64 => {
CodegenTarget::LinuxArm64
| CodegenTarget::DarwinArm64
| CodegenTarget::FreestandingArm64 => {
vec!["~{memory}".to_string(), "~{cc}".to_string()]
}
CodegenTarget::FreestandingRISCV64 => vec!["~{memory}".to_string()],
};

// Empty barrier-like asm blocks must not implicitly clobber every GPR.
Expand Down Expand Up @@ -199,7 +263,9 @@ fn build_default_clobbers(
}

match target {
CodegenTarget::LinuxX86_64 | CodegenTarget::DarwinX86_64 => {
CodegenTarget::LinuxX86_64
| CodegenTarget::DarwinX86_64
| CodegenTarget::FreestandingX86_64 => {
const GPRS: [&str; 16] = [
"rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp", "r8", "r9", "r10",
"r11", "r12", "r13", "r14", "r15",
Expand All @@ -211,7 +277,9 @@ fn build_default_clobbers(
}
}
}
CodegenTarget::LinuxArm64 | CodegenTarget::DarwinArm64 => {
CodegenTarget::LinuxArm64
| CodegenTarget::DarwinArm64
| CodegenTarget::FreestandingArm64 => {
for n in 0..=30u32 {
if n == 18 {
continue;
Expand All @@ -222,6 +290,17 @@ fn build_default_clobbers(
}
}
}
CodegenTarget::FreestandingRISCV64 => {
for n in [
1u32, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 27, 28, 29, 30, 31,
] {
let r = format!("x{}", n);
if !used_phys.contains(&r) {
clobbers.push(format!("~{{{}}}", r));
}
}
}
}

clobbers
Expand Down Expand Up @@ -265,18 +344,26 @@ fn gcc_percent_to_llvm_dollar(s: &str) -> String {

fn normalize_special_clobber(target: CodegenTarget, token: &str) -> Option<String> {
match target {
CodegenTarget::LinuxX86_64 | CodegenTarget::DarwinX86_64 => match token {
CodegenTarget::LinuxX86_64
| CodegenTarget::DarwinX86_64
| CodegenTarget::FreestandingX86_64 => match token {
"memory" => Some("~{memory}".to_string()),
"cc" | "flags" | "eflags" | "rflags" => Some("~{flags}".to_string()),
"dirflag" => Some("~{dirflag}".to_string()),
"fpsr" => Some("~{fpsr}".to_string()),
_ => None,
},
CodegenTarget::LinuxArm64 | CodegenTarget::DarwinArm64 => match token {
CodegenTarget::LinuxArm64
| CodegenTarget::DarwinArm64
| CodegenTarget::FreestandingArm64 => match token {
"memory" => Some("~{memory}".to_string()),
"cc" | "flags" | "eflags" | "rflags" => Some("~{cc}".to_string()),
_ => None,
},
CodegenTarget::FreestandingRISCV64 => match token {
"memory" => Some("~{memory}".to_string()),
_ => None,
},
}
}

Expand Down Expand Up @@ -376,6 +463,13 @@ impl<'a> AsmPlan<'a> {
for (reg, out_target) in outputs_raw {
let t = parse_token(target, reg);

if t.phys_group.is_none() && !is_valid_constraint_class(&t.raw_norm) {
panic!(
"asm output register/constraint '{}' is not valid for target {:?}",
reg, target
);
}

// real reg outputs: disallow duplicates by physical group
if let Some(pg) = &t.phys_group {
if !used_out_phys.insert(pg.clone()) {
Expand Down Expand Up @@ -404,6 +498,13 @@ impl<'a> AsmPlan<'a> {
for (reg, expr) in inputs_raw {
let t = parse_token(target, reg);

if t.phys_group.is_none() && !is_valid_constraint_class(&t.raw_norm) {
panic!(
"asm input register/constraint '{}' is not valid for target {:?}",
reg, target
);
}

// real reg inputs: disallow duplicates by physical group
if let Some(pg) = &t.phys_group {
if !used_in_phys.insert(pg.clone()) {
Expand Down
Loading
Loading