Index: llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp =================================================================== --- llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -1173,7 +1173,8 @@ Parser.getTok().getLoc())); Parser.Lex(); // Eat the [ - if (Mnemonic == "cas" || Mnemonic == "casx" || Mnemonic == "casa") { + if (Mnemonic == "cas" || Mnemonic == "casl" || Mnemonic == "casa" || + Mnemonic == "casx" || Mnemonic == "casxl" || Mnemonic == "casxa") { SMLoc S = Parser.getTok().getLoc(); if (getLexer().getKind() != AsmToken::Percent) return MatchOperand_NoMatch; Index: llvm/lib/Target/Sparc/SparcInstr64Bit.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ llvm/lib/Target/Sparc/SparcInstr64Bit.td @@ -475,14 +475,34 @@ } // ATOMICS. -let Predicates = [Is64Bit], Constraints = "$swap = $rd", asi = 0b10000000 in { - def CASXrr: F3_1_asi<3, 0b111110, +let Predicates = [Is64Bit], Constraints = "$swap = $rd" in { + let asi = 0b10000000 in + def CASXrr: F3_1_asi<3, 0b111110, (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, I64Regs:$swap), "casx [$rs1], $rs2, $rd", [(set i64:$rd, (atomic_cmp_swap_64 i64:$rs1, i64:$rs2, i64:$swap))]>; + let asi = 0b10001000 in + def CASXLrr: F3_1_asi<3, 0b111110, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, + I64Regs:$swap), + "casxl [$rs1], $rs2, $rd", + []>; + + def CASXArr: F3_1_asi<3, 0b111110, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, + I64Regs:$swap, ASITag:$asi), + "casxa [$rs1] $asi, $rs2, $rd", + []>; + + let Uses = [ASI] in + def CASXAri: F3_1_cas_asi<3, 0b111110, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, + I64Regs:$swap), + "casxa [$rs1] %asi, $rs2, $rd", + []>; } // Predicates = [Is64Bit], Constraints = ... let Predicates = [Is64Bit] in { Index: llvm/lib/Target/Sparc/SparcInstrFormats.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrFormats.td +++ llvm/lib/Target/Sparc/SparcInstrFormats.td @@ -135,6 +135,14 @@ let Inst{4-0} = rs2; } +// CAS instructions does not use an immediate even when i=1 +class F3_1_cas_asi opVal, bits<6> op3val, dag outs, dag ins, + string asmstr, list pattern, InstrItinClass itin = NoItinerary> + : F3_1_asi { + let asi = 0; + let Inst{13} = 1; // i field = 1 +} + class F3_1 opVal, bits<6> op3val, dag outs, dag ins, string asmstr, list pattern, InstrItinClass itin = IIC_iu_instr> : F3_1_asi { Index: llvm/lib/Target/Sparc/SparcInstrInfo.td =================================================================== --- llvm/lib/Target/Sparc/SparcInstrInfo.td +++ llvm/lib/Target/Sparc/SparcInstrInfo.td @@ -51,10 +51,13 @@ // point instructions. def HasHardQuad : Predicate<"Subtarget->hasHardQuad()">; -// HasLeonCASA - This is true when the target processor supports the CASA -// instruction +// HasLeonCASA - This is true when the target processor supports the Leon CASA +// instruction. def HasLeonCASA : Predicate<"Subtarget->hasLeonCasa()">; +// HasCASA - This is true when the target processor supports CASA instruction. +def HasCASA : Predicate<"Subtarget->hasLeonCasa() || Subtarget->isV9()">; + // HasPWRPSR - This is true when the target processor supports partial // writes to the PSR register that only affects the ET field. def HasPWRPSR : Predicate<"Subtarget->hasPWRPSR()">, @@ -1700,16 +1703,26 @@ "sir $simm13", []>; // The CAS instruction, unlike other instructions, only comes in a -// form which requires an ASI be provided. The ASI value hardcoded -// here is ASI_PRIMARY, the default unprivileged ASI for SparcV9. -let Predicates = [HasV9], Constraints = "$swap = $rd", asi = 0b10000000 in - def CASrr: F3_1_asi<3, 0b111100, +// form which requires an ASI be provided. +let Predicates = [HasV9], Constraints = "$swap = $rd" in { + // The ASI value hardcoded here is ASI_PRIMARY, the default + // unprivileged ASI for SparcV9. + let asi = 0b10000000 in + def CASrr: F3_1_asi<3, 0b111100, (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, IntRegs:$swap), "cas [$rs1], $rs2, $rd", [(set i32:$rd, (atomic_cmp_swap_32 iPTR:$rs1, i32:$rs2, i32:$swap))]>; + // SparcV9 also specifies a CASL alias, which uses ASI_PRIMARY_LITTLE. + let asi = 0b10001000 in + def CASLrr: F3_1_asi<3, 0b111100, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, + IntRegs:$swap), + "casl [$rs1], $rs2, $rd", + []>; +} // CASA is supported as an instruction on some LEON3 and all LEON4 processors. // This version can be automatically lowered from C code, selecting ASI 10 @@ -1721,15 +1734,23 @@ [(set i32:$rd, (atomic_cmp_swap_32 iPTR:$rs1, i32:$rs2, i32:$swap))]>; -// CASA supported on some LEON3 and all LEON4 processors. Same pattern as -// CASrr, above, but with a different ASI. This version is supported for -// inline assembly lowering only. -let Predicates = [HasLeonCASA], Constraints = "$swap = $rd" in +// CASA supported on all V9, some LEON3 and all LEON4 processors. +// Same pattern as CASrr above, but with a different ASI. +// This version is supported for inline assembly lowering only. +let Predicates = [HasCASA], Constraints = "$swap = $rd" in def CASArr: F3_1_asi<3, 0b111100, (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, IntRegs:$swap, ASITag:$asi), "casa [$rs1] $asi, $rs2, $rd", []>; +// On the other hand, CASA that takes its ASI from a register +// is only supported on V9 processors. +let Predicates = [HasV9], Uses = [ASI], Constraints = "$swap = $rd" in + def CASAri: F3_1_cas_asi<3, 0b111100, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, + IntRegs:$swap), + "casa [$rs1] %asi, $rs2, $rd", []>; + // TODO: Add DAG sequence to lower these instructions. Currently, only provided // as inline assembler-supported instructions. let Predicates = [HasUMAC_SMAC], Defs = [Y, ASR18], Uses = [Y, ASR18] in { Index: llvm/test/MC/Disassembler/Sparc/sparc-atomics.txt =================================================================== --- /dev/null +++ llvm/test/MC/Disassembler/Sparc/sparc-atomics.txt @@ -0,0 +1,25 @@ +# RUN: llvm-mc --disassemble %s -triple=sparcv9-unknown-linux | FileCheck %s + +# CHECK: cas [%i0], %l6, %o2 +0xd5,0xe6,0x10,0x16 + +# CHECK: casl [%i0], %l6, %o2 +0xd5,0xe6,0x11,0x16 + +# CHECK: casa [%i0] 255, %l6, %o2 +0xd5,0xe6,0x1f,0xf6 + +# CHECK: casa [%i0] %asi, %l6, %o2 +0xd5,0xe6,0x20,0x16 + +# CHECK: casx [%i0], %l6, %o2 +0xd5,0xf6,0x10,0x16 + +# CHECK: casxl [%i0], %l6, %o2 +0xd5,0xf6,0x11,0x16 + +# CHECK: casxa [%i0] 255, %l6, %o2 +0xd5,0xf6,0x1f,0xf6 + +# CHECK: casxa [%i0] %asi, %l6, %o2 +0xd5,0xf6,0x20,0x16 Index: llvm/test/MC/Sparc/sparcv9-atomic-instructions.s =================================================================== --- llvm/test/MC/Sparc/sparcv9-atomic-instructions.s +++ llvm/test/MC/Sparc/sparcv9-atomic-instructions.s @@ -21,5 +21,29 @@ ! CHECK: cas [%i0], %l6, %o2 ! encoding: [0xd5,0xe6,0x10,0x16] cas [%i0], %l6, %o2 + ! CHECK: casl [%i0], %l6, %o2 ! encoding: [0xd5,0xe6,0x11,0x16] + casl [%i0], %l6, %o2 + + ! CHECK: casa [%i0] 128, %l6, %o2 ! encoding: [0xd5,0xe6,0x10,0x16] + casa [%i0] 0x80, %l6, %o2 + + ! CHECK: casa [%i0] 128, %l6, %o2 ! encoding: [0xd5,0xe6,0x10,0x16] + casa [%i0] (0x40+0x40), %l6, %o2 + + ! CHECK: casa [%i0] %asi, %l6, %o2 ! encoding: [0xd5,0xe6,0x20,0x16] + casa [%i0] %asi, %l6, %o2 + ! CHECK: casx [%i0], %l6, %o2 ! encoding: [0xd5,0xf6,0x10,0x16] casx [%i0], %l6, %o2 + + ! CHECK: casxl [%i0], %l6, %o2 ! encoding: [0xd5,0xf6,0x11,0x16] + casxl [%i0], %l6, %o2 + + ! CHECK: casxa [%i0] 128, %l6, %o2 ! encoding: [0xd5,0xf6,0x10,0x16] + casxa [%i0] 0x80, %l6, %o2 + + ! CHECK: casxa [%i0] 128, %l6, %o2 ! encoding: [0xd5,0xf6,0x10,0x16] + casxa [%i0] (0x40+0x40), %l6, %o2 + + ! CHECK: casxa [%i0] %asi, %l6, %o2 ! encoding: [0xd5,0xf6,0x20,0x16] + casxa [%i0] %asi, %l6, %o2