Add initial scalar FP operations (addss, subss, etc) to x64 backend.
Adds support for addss and subss. This is the first lowering for sse floating point alu and some move operations. The changes here do some renaming of data structures and adds a couple of new ones to support sse specific operations. The work done here will likely evolve as needed to support an efficient, inituative, and consistent framework.
This commit is contained in:
committed by
Benjamin Bouvier
parent
e5b81bbc28
commit
48f0b10c7a
@@ -48,7 +48,7 @@ pub(crate) struct X64ABIBody {
|
||||
flags: settings::Flags,
|
||||
}
|
||||
|
||||
fn in_int_reg(ty: types::Type) -> bool {
|
||||
fn use_int_reg(ty: types::Type) -> bool {
|
||||
match ty {
|
||||
types::I8
|
||||
| types::I16
|
||||
@@ -63,6 +63,13 @@ fn in_int_reg(ty: types::Type) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn use_flt_reg(ty: types::Type) -> bool {
|
||||
match ty {
|
||||
types::F32 | types::F64 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_intreg_for_arg_systemv(idx: usize) -> Option<Reg> {
|
||||
match idx {
|
||||
0 => Some(regs::rdi()),
|
||||
@@ -75,6 +82,20 @@ fn get_intreg_for_arg_systemv(idx: usize) -> Option<Reg> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fltreg_for_arg_systemv(idx: usize) -> Option<Reg> {
|
||||
match idx {
|
||||
0 => Some(regs::xmm0()),
|
||||
1 => Some(regs::xmm1()),
|
||||
2 => Some(regs::xmm2()),
|
||||
3 => Some(regs::xmm3()),
|
||||
4 => Some(regs::xmm4()),
|
||||
5 => Some(regs::xmm5()),
|
||||
6 => Some(regs::xmm6()),
|
||||
7 => Some(regs::xmm7()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_intreg_for_retval_systemv(idx: usize) -> Option<Reg> {
|
||||
match idx {
|
||||
0 => Some(regs::rax()),
|
||||
@@ -83,6 +104,14 @@ fn get_intreg_for_retval_systemv(idx: usize) -> Option<Reg> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fltreg_for_retval_systemv(idx: usize) -> Option<Reg> {
|
||||
match idx {
|
||||
0 => Some(regs::xmm0()),
|
||||
1 => Some(regs::xmm1()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_callee_save_systemv(r: RealReg) -> bool {
|
||||
use regs::*;
|
||||
match r.get_class() {
|
||||
@@ -90,6 +119,7 @@ fn is_callee_save_systemv(r: RealReg) -> bool {
|
||||
ENC_RBX | ENC_RBP | ENC_R12 | ENC_R13 | ENC_R14 | ENC_R15 => true,
|
||||
_ => false,
|
||||
},
|
||||
RegClass::V128 => false,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
@@ -106,6 +136,7 @@ impl X64ABIBody {
|
||||
// Compute args and retvals from signature.
|
||||
let mut args = vec![];
|
||||
let mut next_int_arg = 0;
|
||||
let mut next_flt_arg = 0;
|
||||
for param in &f.signature.params {
|
||||
match param.purpose {
|
||||
ir::ArgumentPurpose::VMContext if f.signature.call_conv.extends_baldrdash() => {
|
||||
@@ -114,15 +145,22 @@ impl X64ABIBody {
|
||||
}
|
||||
|
||||
ir::ArgumentPurpose::Normal | ir::ArgumentPurpose::VMContext => {
|
||||
if in_int_reg(param.value_type) {
|
||||
if use_int_reg(param.value_type) {
|
||||
if let Some(reg) = get_intreg_for_arg_systemv(next_int_arg) {
|
||||
args.push(ABIArg::Reg(reg.to_real_reg()));
|
||||
} else {
|
||||
unimplemented!("passing arg on the stack");
|
||||
}
|
||||
next_int_arg += 1;
|
||||
} else if use_flt_reg(param.value_type) {
|
||||
if let Some(reg) = get_fltreg_for_arg_systemv(next_flt_arg) {
|
||||
args.push(ABIArg::Reg(reg.to_real_reg()));
|
||||
} else {
|
||||
unimplemented!("passing arg on the stack");
|
||||
}
|
||||
next_flt_arg += 1;
|
||||
} else {
|
||||
unimplemented!("non int normal register")
|
||||
unimplemented!("non int normal register {:?}", param.value_type)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,16 +170,24 @@ impl X64ABIBody {
|
||||
|
||||
let mut rets = vec![];
|
||||
let mut next_int_retval = 0;
|
||||
let mut next_flt_retval = 0;
|
||||
for ret in &f.signature.returns {
|
||||
match ret.purpose {
|
||||
ir::ArgumentPurpose::Normal => {
|
||||
if in_int_reg(ret.value_type) {
|
||||
if use_int_reg(ret.value_type) {
|
||||
if let Some(reg) = get_intreg_for_retval_systemv(next_int_retval) {
|
||||
rets.push(ABIRet::Reg(reg.to_real_reg()));
|
||||
} else {
|
||||
unimplemented!("passing return on the stack");
|
||||
}
|
||||
next_int_retval += 1;
|
||||
} else if use_flt_reg(ret.value_type) {
|
||||
if let Some(reg) = get_fltreg_for_retval_systemv(next_flt_retval) {
|
||||
rets.push(ABIRet::Reg(reg.to_real_reg()));
|
||||
} else {
|
||||
unimplemented!("passing return on the stack");
|
||||
}
|
||||
next_flt_retval += 1;
|
||||
} else {
|
||||
unimplemented!("returning non integer normal value");
|
||||
}
|
||||
@@ -232,8 +278,11 @@ impl ABIBody for X64ABIBody {
|
||||
if from_reg.get_class() == RegClass::I32 || from_reg.get_class() == RegClass::I64 {
|
||||
// TODO do we need a sign extension if it's I32?
|
||||
return Inst::mov_r_r(/*is64=*/ true, from_reg.to_reg(), to_reg);
|
||||
} else if from_reg.get_class() == RegClass::V128 {
|
||||
// TODO: How to support Movss. Should is64 always be true?
|
||||
return Inst::xmm_r_r(SSE_Op::SSE2_Movsd, from_reg.to_reg(), to_reg);
|
||||
}
|
||||
unimplemented!("moving from non-int arg to vreg");
|
||||
unimplemented!("moving from non-int arg to vreg {:?}", from_reg.get_class());
|
||||
}
|
||||
ABIArg::_Stack => unimplemented!("moving from stack arg to vreg"),
|
||||
}
|
||||
@@ -266,8 +315,16 @@ impl ABIBody for X64ABIBody {
|
||||
from_reg.to_reg(),
|
||||
Writable::<Reg>::from_reg(to_reg.to_reg()),
|
||||
))
|
||||
} else if to_reg.get_class() == RegClass::V128
|
||||
|| to_reg.get_class() == RegClass::V128
|
||||
{
|
||||
ret.push(Inst::xmm_r_r(
|
||||
SSE_Op::SSE2_Movsd,
|
||||
from_reg.to_reg(),
|
||||
Writable::<Reg>::from_reg(to_reg.to_reg()),
|
||||
))
|
||||
} else {
|
||||
unimplemented!("moving from vreg to non-int return value");
|
||||
unimplemented!("moving from vreg to unsupported return value");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user