diff --git a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp --- a/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ b/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; diff --git a/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/llvm/lib/Target/Sparc/SparcInstr64Bit.td --- a/llvm/lib/Target/Sparc/SparcInstr64Bit.td +++ b/llvm/lib/Target/Sparc/SparcInstr64Bit.td @@ -475,14 +475,33 @@ } // 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", + []>; + + def CASXAri: F3_1_cas_asi<3, 0b111110, + (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2, + I64Regs:$swap, ASRRegs:$asr), + "casxa [$rs1] $asr, $rs2, $rd", + []>; } // Predicates = [Is64Bit], Constraints = ... let Predicates = [Is64Bit] in { diff --git a/llvm/lib/Target/Sparc/SparcInstrFormats.td b/llvm/lib/Target/Sparc/SparcInstrFormats.td --- a/llvm/lib/Target/Sparc/SparcInstrFormats.td +++ b/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 { diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td --- a/llvm/lib/Target/Sparc/SparcInstrInfo.td +++ b/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 +// HasLeonCASA - This is true when the target processor supports the Leon CASA // instruction def HasLeonCASA : Predicate<"Subtarget->hasLeonCasa()">; +// HasCAS - This is true when the target processor supports CASA instruction. +def HasCAS : 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 = [HasCAS], 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], Constraints = "$swap = $rd" in + def CASAri: F3_1_cas_asi<3, 0b111100, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, + IntRegs:$swap, ASRRegs:$asr), + "casa [$rs1] $asr, $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 { diff --git a/llvm/test/MC/Sparc/sparcv9-atomic-instructions.s b/llvm/test/MC/Sparc/sparcv9-atomic-instructions.s --- a/llvm/test/MC/Sparc/sparcv9-atomic-instructions.s +++ b/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