mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
Encode alignment attribute for cmpxchg
This is a follow up patch to D83136 adding the align attribute to `cmpxchg`. See also D83465 for `atomicrmw`. Differential Revision: https://reviews.llvm.org/D87443
This commit is contained in:
parent
1d36d2af13
commit
d83a14c77d
@ -9617,7 +9617,7 @@ Syntax:
|
||||
|
||||
::
|
||||
|
||||
cmpxchg [weak] [volatile] <ty>* <pointer>, <ty> <cmp>, <ty> <new> [syncscope("<target-scope>")] <success ordering> <failure ordering> ; yields { ty, i1 }
|
||||
cmpxchg [weak] [volatile] <ty>* <pointer>, <ty> <cmp>, <ty> <new> [syncscope("<target-scope>")] <success ordering> <failure ordering>[, align <alignment>] ; yields { ty, i1 }
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
@ -9649,6 +9649,13 @@ stronger than that on success, and the failure ordering cannot be either
|
||||
A ``cmpxchg`` instruction can also take an optional
|
||||
":ref:`syncscope <syncscope>`" argument.
|
||||
|
||||
The instruction can take an optional ``align`` attribute.
|
||||
The alignment must be a power of two greater or equal to the size of the
|
||||
`<value>` type. If unspecified, the alignment is assumed to be equal to the
|
||||
size of the '<value>' type. Note that this default alignment assumption is
|
||||
different from the alignment used for the load/store instructions when align
|
||||
isn't specified.
|
||||
|
||||
The pointer passed into cmpxchg must have alignment greater than or
|
||||
equal to the size in memory of the operand.
|
||||
|
||||
|
@ -7432,7 +7432,8 @@ int LLParser::parseStore(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
|
||||
/// parseCmpXchg
|
||||
/// ::= 'cmpxchg' 'weak'? 'volatile'? TypeAndValue ',' TypeAndValue ','
|
||||
/// TypeAndValue 'singlethread'? AtomicOrdering AtomicOrdering
|
||||
/// TypeAndValue 'singlethread'? AtomicOrdering AtomicOrdering ','
|
||||
/// 'Align'?
|
||||
int LLParser::parseCmpXchg(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
Value *Ptr, *Cmp, *New; LocTy PtrLoc, CmpLoc, NewLoc;
|
||||
bool AteExtraComma = false;
|
||||
@ -7441,6 +7442,7 @@ int LLParser::parseCmpXchg(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
SyncScope::ID SSID = SyncScope::System;
|
||||
bool isVolatile = false;
|
||||
bool isWeak = false;
|
||||
MaybeAlign Alignment;
|
||||
|
||||
if (EatIfPresent(lltok::kw_weak))
|
||||
isWeak = true;
|
||||
@ -7454,7 +7456,8 @@ int LLParser::parseCmpXchg(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
parseToken(lltok::comma, "expected ',' after cmpxchg cmp operand") ||
|
||||
parseTypeAndValue(New, NewLoc, PFS) ||
|
||||
parseScopeAndOrdering(true /*Always atomic*/, SSID, SuccessOrdering) ||
|
||||
parseOrdering(FailureOrdering))
|
||||
parseOrdering(FailureOrdering) ||
|
||||
parseOptionalCommaAlign(Alignment, AteExtraComma))
|
||||
return true;
|
||||
|
||||
if (SuccessOrdering == AtomicOrdering::Unordered ||
|
||||
@ -7476,14 +7479,16 @@ int LLParser::parseCmpXchg(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
if (!New->getType()->isFirstClassType())
|
||||
return error(NewLoc, "cmpxchg operand must be a first class value");
|
||||
|
||||
Align Alignment(
|
||||
const Align DefaultAlignment(
|
||||
PFS.getFunction().getParent()->getDataLayout().getTypeStoreSize(
|
||||
Cmp->getType()));
|
||||
|
||||
AtomicCmpXchgInst *CXI = new AtomicCmpXchgInst(
|
||||
Ptr, Cmp, New, Alignment, SuccessOrdering, FailureOrdering, SSID);
|
||||
Ptr, Cmp, New, Alignment.getValueOr(DefaultAlignment), SuccessOrdering,
|
||||
FailureOrdering, SSID);
|
||||
CXI->setVolatile(isVolatile);
|
||||
CXI->setWeak(isWeak);
|
||||
|
||||
Inst = CXI;
|
||||
return AteExtraComma ? InstExtraComma : InstNormal;
|
||||
}
|
||||
|
@ -5085,7 +5085,7 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
}
|
||||
case bitc::FUNC_CODE_INST_CMPXCHG: {
|
||||
// CMPXCHG: [ptrty, ptr, cmp, val, vol, success_ordering, synchscope,
|
||||
// failure_ordering, weak]
|
||||
// failure_ordering, weak, align?]
|
||||
const size_t NumRecords = Record.size();
|
||||
unsigned OpNum = 0;
|
||||
Value *Ptr = nullptr;
|
||||
@ -5100,10 +5100,14 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
return error("Invalid record");
|
||||
|
||||
Value *Val = nullptr;
|
||||
if (popValue(Record, OpNum, NextValueNo, Cmp->getType(), Val) ||
|
||||
NumRecords < OpNum + 3 || NumRecords > OpNum + 5)
|
||||
if (popValue(Record, OpNum, NextValueNo, Cmp->getType(), Val))
|
||||
return error("Invalid record");
|
||||
|
||||
if (NumRecords < OpNum + 3 || NumRecords > OpNum + 6)
|
||||
return error("Invalid record");
|
||||
|
||||
const bool IsVol = Record[OpNum];
|
||||
|
||||
const AtomicOrdering SuccessOrdering =
|
||||
getDecodedOrdering(Record[OpNum + 1]);
|
||||
if (SuccessOrdering == AtomicOrdering::NotAtomic ||
|
||||
@ -5118,14 +5122,23 @@ Error BitcodeReader::parseFunctionBody(Function *F) {
|
||||
const AtomicOrdering FailureOrdering =
|
||||
getDecodedOrdering(Record[OpNum + 3]);
|
||||
|
||||
const Align Alignment(
|
||||
TheModule->getDataLayout().getTypeStoreSize(Cmp->getType()));
|
||||
const bool IsWeak = Record[OpNum + 4];
|
||||
|
||||
I = new AtomicCmpXchgInst(Ptr, Cmp, Val, Alignment, SuccessOrdering,
|
||||
MaybeAlign Alignment;
|
||||
|
||||
if (NumRecords == (OpNum + 6)) {
|
||||
if (Error Err = parseAlignmentValue(Record[OpNum + 5], Alignment))
|
||||
return Err;
|
||||
}
|
||||
if (!Alignment)
|
||||
Alignment =
|
||||
Align(TheModule->getDataLayout().getTypeStoreSize(Cmp->getType()));
|
||||
|
||||
I = new AtomicCmpXchgInst(Ptr, Cmp, Val, *Alignment, SuccessOrdering,
|
||||
FailureOrdering, SSID);
|
||||
FullTy = StructType::get(Context, {FullTy, Type::getInt1Ty(Context)});
|
||||
cast<AtomicCmpXchgInst>(I)->setVolatile(Record[OpNum]);
|
||||
cast<AtomicCmpXchgInst>(I)->setWeak(Record[OpNum + 4]);
|
||||
cast<AtomicCmpXchgInst>(I)->setVolatile(IsVol);
|
||||
cast<AtomicCmpXchgInst>(I)->setWeak(IsWeak);
|
||||
|
||||
InstructionList.push_back(I);
|
||||
break;
|
||||
|
@ -3060,6 +3060,7 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I,
|
||||
Vals.push_back(
|
||||
getEncodedOrdering(cast<AtomicCmpXchgInst>(I).getFailureOrdering()));
|
||||
Vals.push_back(cast<AtomicCmpXchgInst>(I).isWeak());
|
||||
Vals.push_back(getEncodedAlign(cast<AtomicCmpXchgInst>(I).getAlign()));
|
||||
break;
|
||||
case Instruction::AtomicRMW:
|
||||
Code = bitc::FUNC_CODE_INST_ATOMICRMW;
|
||||
|
@ -4324,6 +4324,7 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
|
||||
} else if (const AtomicCmpXchgInst *CXI = dyn_cast<AtomicCmpXchgInst>(&I)) {
|
||||
writeAtomicCmpXchg(CXI->getContext(), CXI->getSuccessOrdering(),
|
||||
CXI->getFailureOrdering(), CXI->getSyncScopeID());
|
||||
Out << ", align " << CXI->getAlign().value();
|
||||
} else if (const AtomicRMWInst *RMWI = dyn_cast<AtomicRMWInst>(&I)) {
|
||||
writeAtomic(RMWI->getContext(), RMWI->getOrdering(),
|
||||
RMWI->getSyncScopeID());
|
||||
|
@ -718,22 +718,41 @@ normal:
|
||||
|
||||
;; Atomic Memory Ordering Constraints
|
||||
define void @atomics(i32* %word) {
|
||||
%cmpxchg.0 = cmpxchg i32* %word, i32 0, i32 4 monotonic monotonic
|
||||
; CHECK: %cmpxchg.0 = cmpxchg i32* %word, i32 0, i32 4 monotonic monotonic
|
||||
%cmpxchg.1 = cmpxchg i32* %word, i32 0, i32 5 acq_rel monotonic
|
||||
; CHECK: %cmpxchg.1 = cmpxchg i32* %word, i32 0, i32 5 acq_rel monotonic
|
||||
%cmpxchg.2 = cmpxchg i32* %word, i32 0, i32 6 acquire monotonic
|
||||
; CHECK: %cmpxchg.2 = cmpxchg i32* %word, i32 0, i32 6 acquire monotonic
|
||||
%cmpxchg.3 = cmpxchg i32* %word, i32 0, i32 7 release monotonic
|
||||
; CHECK: %cmpxchg.3 = cmpxchg i32* %word, i32 0, i32 7 release monotonic
|
||||
%cmpxchg.4 = cmpxchg i32* %word, i32 0, i32 8 seq_cst monotonic
|
||||
; CHECK: %cmpxchg.4 = cmpxchg i32* %word, i32 0, i32 8 seq_cst monotonic
|
||||
%cmpxchg.5 = cmpxchg weak i32* %word, i32 0, i32 9 seq_cst monotonic
|
||||
; CHECK: %cmpxchg.5 = cmpxchg weak i32* %word, i32 0, i32 9 seq_cst monotonic
|
||||
%cmpxchg.6 = cmpxchg volatile i32* %word, i32 0, i32 10 seq_cst monotonic
|
||||
; CHECK: %cmpxchg.6 = cmpxchg volatile i32* %word, i32 0, i32 10 seq_cst monotonic
|
||||
%cmpxchg.7 = cmpxchg weak volatile i32* %word, i32 0, i32 11 syncscope("singlethread") seq_cst monotonic
|
||||
; CHECK: %cmpxchg.7 = cmpxchg weak volatile i32* %word, i32 0, i32 11 syncscope("singlethread") seq_cst monotonic
|
||||
;; Atomic Compare And Exchange w/o alignment
|
||||
%cmpxchg_no_align.0 = cmpxchg i32* %word, i32 0, i32 4 monotonic monotonic
|
||||
; CHECK: %cmpxchg_no_align.0 = cmpxchg i32* %word, i32 0, i32 4 monotonic monotonic
|
||||
%cmpxchg_no_align.1 = cmpxchg i32* %word, i32 0, i32 5 acq_rel monotonic
|
||||
; CHECK: %cmpxchg_no_align.1 = cmpxchg i32* %word, i32 0, i32 5 acq_rel monotonic
|
||||
%cmpxchg_no_align.2 = cmpxchg i32* %word, i32 0, i32 6 acquire monotonic
|
||||
; CHECK: %cmpxchg_no_align.2 = cmpxchg i32* %word, i32 0, i32 6 acquire monotonic
|
||||
%cmpxchg_no_align.3 = cmpxchg i32* %word, i32 0, i32 7 release monotonic
|
||||
; CHECK: %cmpxchg_no_align.3 = cmpxchg i32* %word, i32 0, i32 7 release monotonic
|
||||
%cmpxchg_no_align.4 = cmpxchg i32* %word, i32 0, i32 8 seq_cst monotonic
|
||||
; CHECK: %cmpxchg_no_align.4 = cmpxchg i32* %word, i32 0, i32 8 seq_cst monotonic
|
||||
%cmpxchg_no_align.5 = cmpxchg weak i32* %word, i32 0, i32 9 seq_cst monotonic
|
||||
; CHECK: %cmpxchg_no_align.5 = cmpxchg weak i32* %word, i32 0, i32 9 seq_cst monotonic
|
||||
%cmpxchg_no_align.6 = cmpxchg volatile i32* %word, i32 0, i32 10 seq_cst monotonic
|
||||
; CHECK: %cmpxchg_no_align.6 = cmpxchg volatile i32* %word, i32 0, i32 10 seq_cst monotonic
|
||||
%cmpxchg_no_align.7 = cmpxchg weak volatile i32* %word, i32 0, i32 11 syncscope("singlethread") seq_cst monotonic
|
||||
; CHECK: %cmpxchg_no_align.7 = cmpxchg weak volatile i32* %word, i32 0, i32 11 syncscope("singlethread") seq_cst monotonic
|
||||
|
||||
;; Atomic Compare And Exchange w/ alignment
|
||||
%cmpxchg.0 = cmpxchg i32* %word, i32 0, i32 4 monotonic monotonic, align 16
|
||||
; CHECK: %cmpxchg.0 = cmpxchg i32* %word, i32 0, i32 4 monotonic monotonic, align 16
|
||||
%cmpxchg.1 = cmpxchg i32* %word, i32 0, i32 5 acq_rel monotonic, align 16
|
||||
; CHECK: %cmpxchg.1 = cmpxchg i32* %word, i32 0, i32 5 acq_rel monotonic, align 16
|
||||
%cmpxchg.2 = cmpxchg i32* %word, i32 0, i32 6 acquire monotonic, align 16
|
||||
; CHECK: %cmpxchg.2 = cmpxchg i32* %word, i32 0, i32 6 acquire monotonic, align 16
|
||||
%cmpxchg.3 = cmpxchg i32* %word, i32 0, i32 7 release monotonic, align 16
|
||||
; CHECK: %cmpxchg.3 = cmpxchg i32* %word, i32 0, i32 7 release monotonic, align 16
|
||||
%cmpxchg.4 = cmpxchg i32* %word, i32 0, i32 8 seq_cst monotonic, align 16
|
||||
; CHECK: %cmpxchg.4 = cmpxchg i32* %word, i32 0, i32 8 seq_cst monotonic, align 16
|
||||
%cmpxchg.5 = cmpxchg weak i32* %word, i32 0, i32 9 seq_cst monotonic, align 16
|
||||
; CHECK: %cmpxchg.5 = cmpxchg weak i32* %word, i32 0, i32 9 seq_cst monotonic, align 16
|
||||
%cmpxchg.6 = cmpxchg volatile i32* %word, i32 0, i32 10 seq_cst monotonic, align 16
|
||||
; CHECK: %cmpxchg.6 = cmpxchg volatile i32* %word, i32 0, i32 10 seq_cst monotonic, align 16
|
||||
%cmpxchg.7 = cmpxchg weak volatile i32* %word, i32 0, i32 11 syncscope("singlethread") seq_cst monotonic, align 16
|
||||
; CHECK: %cmpxchg.7 = cmpxchg weak volatile i32* %word, i32 0, i32 11 syncscope("singlethread") seq_cst monotonic, align 16
|
||||
|
||||
;; Atomic w/o alignment
|
||||
%atomicrmw_no_align.xchg = atomicrmw xchg i32* %word, i32 12 monotonic
|
||||
@ -782,7 +801,7 @@ define void @atomics(i32* %word) {
|
||||
; CHECK: %atomicrmw.umax = atomicrmw umax i32* %word, i32 21 syncscope("singlethread") monotonic, align 16
|
||||
%atomicrmw.umin = atomicrmw volatile umin i32* %word, i32 22 syncscope("singlethread") monotonic, align 16
|
||||
; CHECK: %atomicrmw.umin = atomicrmw volatile umin i32* %word, i32 22 syncscope("singlethread") monotonic, align 16
|
||||
|
||||
|
||||
fence acquire
|
||||
; CHECK: fence acquire
|
||||
fence release
|
||||
|
Loading…
Reference in New Issue
Block a user