Add clobber-only register classes for asm!
These are needed to properly express a function call ABI using a clobber list, even though we don't support passing actual values into/out of these registers.
This commit is contained in:
parent
1e13a9bb33
commit
e1c3f5e017
@ -199,6 +199,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
|
||||
}
|
||||
);
|
||||
|
||||
// Some register classes can only be used as clobbers. This
|
||||
// means that we disallow passing a value in/out of the asm and
|
||||
// require that the operand name an explicit register, not a
|
||||
// register class.
|
||||
if reg_class.is_clobber_only(asm_arch.unwrap())
|
||||
&& !(is_clobber && matches!(reg, asm::InlineAsmRegOrRegClass::Reg(_)))
|
||||
{
|
||||
let msg = format!(
|
||||
"register class `{}` can only be used as a clobber, \
|
||||
not as an input or output",
|
||||
reg_class.name()
|
||||
);
|
||||
sess.struct_span_err(op_sp, &msg).emit();
|
||||
continue;
|
||||
}
|
||||
|
||||
if !is_clobber {
|
||||
// Validate register classes against currently enabled target
|
||||
// features. We check that at least one type is available for
|
||||
|
@ -128,6 +128,7 @@ fn codegen_inline_asm(
|
||||
let mut clobbers = vec![];
|
||||
let mut output_types = vec![];
|
||||
let mut op_idx = FxHashMap::default();
|
||||
let mut clobbered_x87 = false;
|
||||
for (idx, op) in operands.iter().enumerate() {
|
||||
match *op {
|
||||
InlineAsmOperandRef::Out { reg, late, place } => {
|
||||
@ -150,7 +151,27 @@ fn codegen_inline_asm(
|
||||
let ty = if let Some(ref place) = place {
|
||||
layout = Some(&place.layout);
|
||||
llvm_fixup_output_type(self.cx, reg.reg_class(), &place.layout)
|
||||
} else if !is_target_supported(reg.reg_class()) {
|
||||
} else if matches!(
|
||||
reg.reg_class(),
|
||||
InlineAsmRegClass::X86(
|
||||
X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::x87_reg
|
||||
)
|
||||
) {
|
||||
// Special handling for x87/mmx registers: we always
|
||||
// clobber the whole set if one register is marked as
|
||||
// clobbered. This is due to the way LLVM handles the
|
||||
// FP stack in inline assembly.
|
||||
if !clobbered_x87 {
|
||||
clobbered_x87 = true;
|
||||
clobbers.push("~{st}".to_string());
|
||||
for i in 1..=7 {
|
||||
clobbers.push(format!("~{{st({})}}", i));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
} else if !is_target_supported(reg.reg_class())
|
||||
|| reg.reg_class().is_clobber_only(asm_arch)
|
||||
{
|
||||
// We turn discarded outputs into clobber constraints
|
||||
// if the target feature needed by the register class is
|
||||
// disabled. This is necessary otherwise LLVM will try
|
||||
@ -564,6 +585,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => "l",
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
|
||||
@ -585,6 +609,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
|
||||
@ -592,6 +619,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>)
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "^Yk",
|
||||
InlineAsmRegClass::X86(
|
||||
X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
|
||||
) => unreachable!("clobber-only"),
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
@ -614,6 +644,9 @@ fn modifier_to_llvm(
|
||||
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
|
||||
if modifier == Some('v') { None } else { modifier }
|
||||
}
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => None,
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
|
||||
@ -636,6 +669,9 @@ fn modifier_to_llvm(
|
||||
InlineAsmRegClass::PowerPC(_) => None,
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None,
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier {
|
||||
None if arch == InlineAsmArch::X86_64 => Some('q'),
|
||||
@ -660,6 +696,9 @@ fn modifier_to_llvm(
|
||||
_ => unreachable!(),
|
||||
},
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => None,
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
@ -677,6 +716,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
|
||||
| InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
|
||||
cx.type_vector(cx.type_i64(), 2)
|
||||
}
|
||||
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(),
|
||||
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
|
||||
@ -700,6 +742,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
|
||||
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
|
||||
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(),
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(),
|
||||
@ -707,6 +752,9 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
|
||||
| InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
|
||||
InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
|
||||
unreachable!("clobber-only")
|
||||
}
|
||||
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
|
||||
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
|
||||
bug!("LLVM backend does not support SPIR-V")
|
||||
|
@ -752,6 +752,7 @@
|
||||
minnumf64,
|
||||
mips_target_feature,
|
||||
misc,
|
||||
mmx_reg,
|
||||
modifiers,
|
||||
module,
|
||||
module_path,
|
||||
@ -894,6 +895,7 @@
|
||||
prefetch_read_instruction,
|
||||
prefetch_write_data,
|
||||
prefetch_write_instruction,
|
||||
preg,
|
||||
prelude,
|
||||
prelude_import,
|
||||
preserves_flags,
|
||||
@ -1333,6 +1335,7 @@
|
||||
wrapping_mul,
|
||||
wrapping_sub,
|
||||
write_bytes,
|
||||
x87_reg,
|
||||
xmm_reg,
|
||||
ymm_reg,
|
||||
zmm_reg,
|
||||
|
@ -7,6 +7,7 @@
|
||||
reg,
|
||||
vreg,
|
||||
vreg_low16,
|
||||
preg,
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +16,7 @@ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
|
||||
match self {
|
||||
Self::reg => &['w', 'x'],
|
||||
Self::vreg | Self::vreg_low16 => &['b', 'h', 's', 'd', 'q', 'v'],
|
||||
Self::preg => &[],
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,6 +42,7 @@ pub fn suggest_modifier(
|
||||
128 => Some(('q', "q0")),
|
||||
_ => None,
|
||||
},
|
||||
Self::preg => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,6 +50,7 @@ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static st
|
||||
match self {
|
||||
Self::reg => Some(('x', "x0")),
|
||||
Self::vreg | Self::vreg_low16 => Some(('v', "v0")),
|
||||
Self::preg => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,6 +65,7 @@ pub fn supported_types(
|
||||
VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1),
|
||||
VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2);
|
||||
},
|
||||
Self::preg => &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,6 +132,23 @@ pub fn supported_types(
|
||||
v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"],
|
||||
v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"],
|
||||
v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"],
|
||||
p0: preg = ["p0"],
|
||||
p1: preg = ["p1"],
|
||||
p2: preg = ["p2"],
|
||||
p3: preg = ["p3"],
|
||||
p4: preg = ["p4"],
|
||||
p5: preg = ["p5"],
|
||||
p6: preg = ["p6"],
|
||||
p7: preg = ["p7"],
|
||||
p8: preg = ["p8"],
|
||||
p9: preg = ["p9"],
|
||||
p10: preg = ["p10"],
|
||||
p11: preg = ["p11"],
|
||||
p12: preg = ["p12"],
|
||||
p13: preg = ["p13"],
|
||||
p14: preg = ["p14"],
|
||||
p15: preg = ["p15"],
|
||||
ffr: preg = ["ffr"],
|
||||
#error = ["x18", "w18"] =>
|
||||
"x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm",
|
||||
#error = ["x19", "w19"] =>
|
||||
|
@ -513,6 +513,12 @@ pub fn valid_modifiers(self, arch: InlineAsmArch) -> &'static [char] {
|
||||
Self::Err => unreachable!("Use of InlineAsmRegClass::Err"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether registers in this class can only be used as clobbers
|
||||
/// and not as inputs/outputs.
|
||||
pub fn is_clobber_only(self, arch: InlineAsmArch) -> bool {
|
||||
self.supported_types(arch).is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(
|
||||
|
@ -7,6 +7,7 @@
|
||||
RiscV RiscVInlineAsmRegClass {
|
||||
reg,
|
||||
freg,
|
||||
vreg,
|
||||
}
|
||||
}
|
||||
|
||||
@ -44,6 +45,7 @@ pub fn supported_types(
|
||||
}
|
||||
}
|
||||
Self::freg => types! { "f": F32; "d": F64; },
|
||||
Self::vreg => &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -120,6 +122,38 @@ fn not_e(
|
||||
f29: freg = ["f29", "ft9"],
|
||||
f30: freg = ["f30", "ft10"],
|
||||
f31: freg = ["f31", "ft11"],
|
||||
v0: vreg = ["v0"],
|
||||
v1: vreg = ["v1"],
|
||||
v2: vreg = ["v2"],
|
||||
v3: vreg = ["v3"],
|
||||
v4: vreg = ["v4"],
|
||||
v5: vreg = ["v5"],
|
||||
v6: vreg = ["v6"],
|
||||
v7: vreg = ["v7"],
|
||||
v8: vreg = ["v8"],
|
||||
v9: vreg = ["v9"],
|
||||
v10: vreg = ["v10"],
|
||||
v11: vreg = ["v11"],
|
||||
v12: vreg = ["v12"],
|
||||
v13: vreg = ["v13"],
|
||||
v14: vreg = ["v14"],
|
||||
v15: vreg = ["v15"],
|
||||
v16: vreg = ["v16"],
|
||||
v17: vreg = ["v17"],
|
||||
v18: vreg = ["v18"],
|
||||
v19: vreg = ["v19"],
|
||||
v20: vreg = ["v20"],
|
||||
v21: vreg = ["v21"],
|
||||
v22: vreg = ["v22"],
|
||||
v23: vreg = ["v23"],
|
||||
v24: vreg = ["v24"],
|
||||
v25: vreg = ["v25"],
|
||||
v26: vreg = ["v26"],
|
||||
v27: vreg = ["v27"],
|
||||
v28: vreg = ["v28"],
|
||||
v29: vreg = ["v29"],
|
||||
v30: vreg = ["v30"],
|
||||
v31: vreg = ["v31"],
|
||||
#error = ["x9", "s1"] =>
|
||||
"s1 is used internally by LLVM and cannot be used as an operand for inline asm",
|
||||
#error = ["x8", "s0", "fp"] =>
|
||||
|
@ -12,6 +12,8 @@
|
||||
ymm_reg,
|
||||
zmm_reg,
|
||||
kreg,
|
||||
mmx_reg,
|
||||
x87_reg,
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +37,7 @@ pub fn valid_modifiers(self, arch: super::InlineAsmArch) -> &'static [char] {
|
||||
Self::reg_byte => &[],
|
||||
Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'],
|
||||
Self::kreg => &[],
|
||||
Self::mmx_reg | Self::x87_reg => &[],
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,6 +76,7 @@ pub fn suggest_modifier(
|
||||
_ => Some(('x', "xmm0")),
|
||||
},
|
||||
Self::kreg => None,
|
||||
Self::mmx_reg | Self::x87_reg => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +94,7 @@ pub fn default_modifier(self, arch: InlineAsmArch) -> Option<(char, &'static str
|
||||
Self::ymm_reg => Some(('y', "ymm0")),
|
||||
Self::zmm_reg => Some(('z', "zmm0")),
|
||||
Self::kreg => None,
|
||||
Self::mmx_reg | Self::x87_reg => None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,6 +130,7 @@ pub fn supported_types(
|
||||
"avx512f": I8, I16;
|
||||
"avx512bw": I32, I64;
|
||||
},
|
||||
Self::mmx_reg | Self::x87_reg => &[],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -285,16 +291,28 @@ fn esi_reserved(
|
||||
k5: kreg = ["k5"],
|
||||
k6: kreg = ["k6"],
|
||||
k7: kreg = ["k7"],
|
||||
mm0: mmx_reg = ["mm0"],
|
||||
mm1: mmx_reg = ["mm1"],
|
||||
mm2: mmx_reg = ["mm2"],
|
||||
mm3: mmx_reg = ["mm3"],
|
||||
mm4: mmx_reg = ["mm4"],
|
||||
mm5: mmx_reg = ["mm5"],
|
||||
mm6: mmx_reg = ["mm6"],
|
||||
mm7: mmx_reg = ["mm7"],
|
||||
st0: x87_reg = ["st(0)", "st"],
|
||||
st1: x87_reg = ["st(1)"],
|
||||
st2: x87_reg = ["st(2)"],
|
||||
st3: x87_reg = ["st(3)"],
|
||||
st4: x87_reg = ["st(4)"],
|
||||
st5: x87_reg = ["st(5)"],
|
||||
st6: x87_reg = ["st(6)"],
|
||||
st7: x87_reg = ["st(7)"],
|
||||
#error = ["bp", "bpl", "ebp", "rbp"] =>
|
||||
"the frame pointer cannot be used as an operand for inline asm",
|
||||
#error = ["sp", "spl", "esp", "rsp"] =>
|
||||
"the stack pointer cannot be used as an operand for inline asm",
|
||||
#error = ["ip", "eip", "rip"] =>
|
||||
"the instruction pointer cannot be used as an operand for inline asm",
|
||||
#error = ["st", "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"] =>
|
||||
"x87 registers are not currently supported as operands for inline asm",
|
||||
#error = ["mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"] =>
|
||||
"MMX registers are not currently supported as operands for inline asm",
|
||||
#error = ["k0"] =>
|
||||
"the k0 AVX mask register cannot be used as an operand for inline asm",
|
||||
}
|
||||
|
@ -544,9 +544,12 @@ Here is the list of currently supported register classes:
|
||||
| x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` |
|
||||
| x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` |
|
||||
| x86 | `kreg` | `k[1-7]` | `Yk` |
|
||||
| x86 | `x87_reg` | `st([0-7])` | Only clobbers |
|
||||
| x86 | `mmx_reg` | `mm[0-7]` | Only clobbers |
|
||||
| AArch64 | `reg` | `x[0-30]` | `r` |
|
||||
| AArch64 | `vreg` | `v[0-31]` | `w` |
|
||||
| AArch64 | `vreg_low16` | `v[0-15]` | `x` |
|
||||
| AArch64 | `preg` | `p[0-15]`, `ffr` | Only clobbers |
|
||||
| ARM | `reg` | `r[0-12]`, `r14` | `r` |
|
||||
| ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
|
||||
| ARM (ARM) | `reg_thumb` | `r[0-r12]`, `r14` | `l` |
|
||||
@ -565,6 +568,7 @@ Here is the list of currently supported register classes:
|
||||
| NVPTX | `reg64` | None\* | `l` |
|
||||
| RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` |
|
||||
| RISC-V | `freg` | `f[0-31]` | `f` |
|
||||
| RISC-V | `vreg` | `v[0-31]` | Only clobbers |
|
||||
| Hexagon | `reg` | `r[0-28]` | `r` |
|
||||
| PowerPC | `reg` | `r[0-31]` | `r` |
|
||||
| PowerPC | `reg_nonzero` | | `r[1-31]` | `b` |
|
||||
@ -578,6 +582,8 @@ Here is the list of currently supported register classes:
|
||||
> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
|
||||
>
|
||||
> Note #4: WebAssembly doesn't have registers, so named registers are not supported.
|
||||
>
|
||||
> Note #5: Some register classes are marked as "Only clobbers" which means that they cannot be used for inputs or outputs, only clobbers of the form `out("reg") _` or `lateout("reg") _`.
|
||||
|
||||
Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
|
||||
|
||||
@ -593,8 +599,11 @@ Each register class has constraints on which value types they can be used with.
|
||||
| x86 | `zmm_reg` | `avx512f` | `i32`, `f32`, `i64`, `f64`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` <br> `i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` <br> `i8x64`, `i16x32`, `i32x16`, `i64x8`, `f32x16`, `f64x8` |
|
||||
| x86 | `kreg` | `axv512f` | `i8`, `i16` |
|
||||
| x86 | `kreg` | `axv512bw` | `i32`, `i64` |
|
||||
| x86 | `mmx_reg` | N/A | Only clobbers |
|
||||
| x86 | `x87_reg` | N/A | Only clobbers |
|
||||
| AArch64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
|
||||
| AArch64 | `vreg` | `fp` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
|
||||
| AArch64 | `preg` | N/A | Only clobbers |
|
||||
| ARM | `reg` | None | `i8`, `i16`, `i32`, `f32` |
|
||||
| ARM | `sreg` | `vfp2` | `i32`, `f32` |
|
||||
| ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` |
|
||||
@ -610,6 +619,7 @@ Each register class has constraints on which value types they can be used with.
|
||||
| RISC-V64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
|
||||
| RISC-V | `freg` | `f` | `f32` |
|
||||
| RISC-V | `freg` | `d` | `f64` |
|
||||
| RISC-V | `vreg` | N/A | Only clobbers |
|
||||
| Hexagon | `reg` | None | `i8`, `i16`, `i32`, `f32` |
|
||||
| PowerPC | `reg` | None | `i8`, `i16`, `i32` |
|
||||
| PowerPC | `reg_nonzero` | None | `i8`, `i16`, `i32` |
|
||||
|
19
src/test/codegen/asm-clobbers.rs
Normal file
19
src/test/codegen/asm-clobbers.rs
Normal file
@ -0,0 +1,19 @@
|
||||
// compile-flags: -O
|
||||
// only-x86_64
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(asm)]
|
||||
|
||||
// CHECK-LABEL: @x87_clobber
|
||||
// CHECK: ~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)}
|
||||
#[no_mangle]
|
||||
pub unsafe fn x87_clobber() {
|
||||
asm!("foo", out("st") _);
|
||||
}
|
||||
|
||||
// CHECK-LABEL: @mmx_clobber
|
||||
// CHECK: ~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)}
|
||||
#[no_mangle]
|
||||
pub unsafe fn mmx_clobber() {
|
||||
asm!("bar", out("mm0") _, out("mm1") _);
|
||||
}
|
@ -31,15 +31,26 @@ fn main() {
|
||||
//~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand
|
||||
asm!("", in("ip") foo);
|
||||
//~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
|
||||
asm!("", in("st(2)") foo);
|
||||
//~^ ERROR invalid register `st(2)`: x87 registers are not currently supported as operands
|
||||
asm!("", in("mm0") foo);
|
||||
//~^ ERROR invalid register `mm0`: MMX registers are not currently supported as operands
|
||||
asm!("", in("k0") foo);
|
||||
//~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
|
||||
asm!("", in("ah") foo);
|
||||
//~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand
|
||||
|
||||
asm!("", in("st(2)") foo);
|
||||
//~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
|
||||
asm!("", in("mm0") foo);
|
||||
//~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
|
||||
asm!("", out("st(2)") _);
|
||||
asm!("", out("mm0") _);
|
||||
asm!("{}", in(x87_reg) foo);
|
||||
//~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
|
||||
asm!("{}", in(mmx_reg) foo);
|
||||
//~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
|
||||
asm!("{}", out(x87_reg) _);
|
||||
//~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
|
||||
asm!("{}", out(mmx_reg) _);
|
||||
//~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
|
||||
|
||||
// Explicit register conflicts
|
||||
// (except in/lateout which don't conflict)
|
||||
|
||||
|
@ -76,32 +76,56 @@ error: invalid register `ip`: the instruction pointer cannot be used as an opera
|
||||
LL | asm!("", in("ip") foo);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: invalid register `st(2)`: x87 registers are not currently supported as operands for inline asm
|
||||
--> $DIR/bad-reg.rs:34:18
|
||||
|
|
||||
LL | asm!("", in("st(2)") foo);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid register `mm0`: MMX registers are not currently supported as operands for inline asm
|
||||
--> $DIR/bad-reg.rs:36:18
|
||||
|
|
||||
LL | asm!("", in("mm0") foo);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
|
||||
--> $DIR/bad-reg.rs:38:18
|
||||
--> $DIR/bad-reg.rs:34:18
|
||||
|
|
||||
LL | asm!("", in("k0") foo);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64
|
||||
--> $DIR/bad-reg.rs:40:18
|
||||
--> $DIR/bad-reg.rs:36:18
|
||||
|
|
||||
LL | asm!("", in("ah") foo);
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: register class `x87_reg` can only be used as a clobber, not as an input or output
|
||||
--> $DIR/bad-reg.rs:39:18
|
||||
|
|
||||
LL | asm!("", in("st(2)") foo);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
|
||||
--> $DIR/bad-reg.rs:41:18
|
||||
|
|
||||
LL | asm!("", in("mm0") foo);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: register class `x87_reg` can only be used as a clobber, not as an input or output
|
||||
--> $DIR/bad-reg.rs:45:20
|
||||
|
|
||||
LL | asm!("{}", in(x87_reg) foo);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
|
||||
--> $DIR/bad-reg.rs:47:20
|
||||
|
|
||||
LL | asm!("{}", in(mmx_reg) foo);
|
||||
| ^^^^^^^^^^^^^^^
|
||||
|
||||
error: register class `x87_reg` can only be used as a clobber, not as an input or output
|
||||
--> $DIR/bad-reg.rs:49:20
|
||||
|
|
||||
LL | asm!("{}", out(x87_reg) _);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: register class `mmx_reg` can only be used as a clobber, not as an input or output
|
||||
--> $DIR/bad-reg.rs:51:20
|
||||
|
|
||||
LL | asm!("{}", out(mmx_reg) _);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: register `al` conflicts with register `ax`
|
||||
--> $DIR/bad-reg.rs:46:33
|
||||
--> $DIR/bad-reg.rs:57:33
|
||||
|
|
||||
LL | asm!("", in("eax") foo, in("al") bar);
|
||||
| ------------- ^^^^^^^^^^^^ register `al`
|
||||
@ -109,7 +133,7 @@ LL | asm!("", in("eax") foo, in("al") bar);
|
||||
| register `ax`
|
||||
|
||||
error: register `ax` conflicts with register `ax`
|
||||
--> $DIR/bad-reg.rs:48:33
|
||||
--> $DIR/bad-reg.rs:59:33
|
||||
|
|
||||
LL | asm!("", in("rax") foo, out("rax") bar);
|
||||
| ------------- ^^^^^^^^^^^^^^ register `ax`
|
||||
@ -117,13 +141,13 @@ LL | asm!("", in("rax") foo, out("rax") bar);
|
||||
| register `ax`
|
||||
|
|
||||
help: use `lateout` instead of `out` to avoid conflict
|
||||
--> $DIR/bad-reg.rs:48:18
|
||||
--> $DIR/bad-reg.rs:59:18
|
||||
|
|
||||
LL | asm!("", in("rax") foo, out("rax") bar);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: register `ymm0` conflicts with register `xmm0`
|
||||
--> $DIR/bad-reg.rs:51:34
|
||||
--> $DIR/bad-reg.rs:62:34
|
||||
|
|
||||
LL | asm!("", in("xmm0") foo, in("ymm0") bar);
|
||||
| -------------- ^^^^^^^^^^^^^^ register `ymm0`
|
||||
@ -131,7 +155,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar);
|
||||
| register `xmm0`
|
||||
|
||||
error: register `ymm0` conflicts with register `xmm0`
|
||||
--> $DIR/bad-reg.rs:53:34
|
||||
--> $DIR/bad-reg.rs:64:34
|
||||
|
|
||||
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
|
||||
| -------------- ^^^^^^^^^^^^^^^ register `ymm0`
|
||||
@ -139,10 +163,10 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar);
|
||||
| register `xmm0`
|
||||
|
|
||||
help: use `lateout` instead of `out` to avoid conflict
|
||||
--> $DIR/bad-reg.rs:53:18
|
||||
--> $DIR/bad-reg.rs:64:18
|
||||
|
|
||||
LL | asm!("", in("xmm0") foo, out("ymm0") bar);
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 19 previous errors
|
||||
error: aborting due to 23 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user