Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -3590,10 +3590,14 @@ - ``K``: An immediate signed 16-bit integer. - ``L``: An immediate signed 20-bit integer. - ``M``: An immediate integer 0x7fffffff. -- ``Q``, ``R``: A memory address operand with a base address and a 12-bit - immediate unsigned displacement. -- ``S``, ``T``: A memory address operand with a base address and a 20-bit - immediate signed displacement. +- ``Q``: A memory address operand with a base address and a 12-bit immediate + unsigned displacement. +- ``R``: A memory address operand with a base address, a 12-bit immediate + unsigned displacement, and an index register. +- ``S``: A memory address operand with a base address and a 20-bit immediate + unsigned displacement. +- ``T``: A memory address operand with a base address, a 20-bit immediate + unsigned displacement, and an index register. - ``r`` or ``d``: A 32, 64, or 128-bit integer register. - ``a``: A 32, 64, or 128-bit integer address register (excludes R0, which in an address context evaluates as zero). @@ -4835,10 +4839,10 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The ``invariant.group`` metadata may be attached to ``load``/``store`` instructions. -The existence of the ``invariant.group`` metadata on the instruction tells -the optimizer that every ``load`` and ``store`` to the same pointer operand -within the same invariant group can be assumed to load or store the same -value (but see the ``llvm.invariant.group.barrier`` intrinsic which affects +The existence of the ``invariant.group`` metadata on the instruction tells +the optimizer that every ``load`` and ``store`` to the same pointer operand +within the same invariant group can be assumed to load or store the same +value (but see the ``llvm.invariant.group.barrier`` intrinsic which affects when two pointers are considered the same). Examples: @@ -4850,26 +4854,26 @@ %ptr = alloca i8 store i8 42, i8* %ptr, !invariant.group !0 call void @foo(i8* %ptr) - + %a = load i8, i8* %ptr, !invariant.group !0 ; Can assume that value under %ptr didn't change call void @foo(i8* %ptr) %b = load i8, i8* %ptr, !invariant.group !1 ; Can't assume anything, because group changed - - %newPtr = call i8* @getPointer(i8* %ptr) + + %newPtr = call i8* @getPointer(i8* %ptr) %c = load i8, i8* %newPtr, !invariant.group !0 ; Can't assume anything, because we only have information about %ptr - + %unknownValue = load i8, i8* @unknownPtr store i8 %unknownValue, i8* %ptr, !invariant.group !0 ; Can assume that %unknownValue == 42 - + call void @foo(i8* %ptr) %newPtr2 = call i8* @llvm.invariant.group.barrier(i8* %ptr) %d = load i8, i8* %newPtr2, !invariant.group !0 ; Can't step through invariant.group.barrier to get value of %ptr - + ... declare void @foo(i8*) declare i8* @getPointer(i8*) declare i8* @llvm.invariant.group.barrier(i8*) - + !0 = !{!"magic ptr"} !1 = !{!"other ptr"} @@ -7140,7 +7144,7 @@ instructions to save cache bandwidth, such as the ``MOVNT`` instruction on x86. -The optional ``!invariant.group`` metadata must reference a +The optional ``!invariant.group`` metadata must reference a single metadata name ````. See ``invariant.group`` metadata. Semantics: @@ -7246,10 +7250,10 @@ to operate on, a value to compare to the value currently be at that address, and a new value to place at that address if the compared values are equal. The type of '' must be an integer or pointer type whose -bit width is a power of two greater than or equal to eight and less +bit width is a power of two greater than or equal to eight and less than or equal to a target-specific size limit. '' and '' must -have the same type, and the type of '' must be a pointer to -that type. If the ``cmpxchg`` is marked as ``volatile``, then the +have the same type, and the type of '' must be a pointer to +that type. If the ``cmpxchg`` is marked as ``volatile``, then the optimizer is not allowed to modify the number or order of execution of this ``cmpxchg`` with other :ref:`volatile operations `. @@ -8522,7 +8526,7 @@ ``tail`` or ``musttail`` markers to the call. It is used to prevent tail call optimization from being performed on the call. -#. The optional ``fast-math flags`` marker indicates that the call has one or more +#. The optional ``fast-math flags`` marker indicates that the call has one or more :ref:`fast-math flags `, which are optimization hints to enable otherwise unsafe floating-point optimizations. Fast-math flags are only valid for calls that return a floating-point scalar or vector type. @@ -11879,7 +11883,7 @@ Overview: """"""""" -The '``llvm.invariant.group.barrier``' intrinsic can be used when an invariant +The '``llvm.invariant.group.barrier``' intrinsic can be used when an invariant established by invariant.group metadata no longer holds, to obtain a new pointer value that does not carry the invariant information. @@ -11893,7 +11897,7 @@ Semantics: """""""""" -Returns another pointer that aliases its argument but which is considered different +Returns another pointer that aliases its argument but which is considered different for the purposes of ``load``/``store`` ``invariant.group`` metadata. General Intrinsics Index: lib/Target/SystemZ/README.txt =================================================================== --- lib/Target/SystemZ/README.txt +++ lib/Target/SystemZ/README.txt @@ -7,12 +7,6 @@ -- -SystemZDAGToDAGISel::SelectInlineAsmMemoryOperand() treats the Q and R -constraints the same, and the S and T constraints the same, because the optional -index is not used. - --- - If an inline asm ties an i32 "r" result to an i64 input, the input will be treated as an i32, leaving the upper bits uninitialised. For example: Index: lib/Target/SystemZ/SystemZISelDAGToDAG.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -1322,6 +1322,8 @@ SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector &OutOps) { + SystemZAddressingMode::AddrForm Form; + SystemZAddressingMode::DispRange DispRange; SDValue Base, Disp, Index; switch(ConstraintID) { @@ -1329,33 +1331,35 @@ llvm_unreachable("Unexpected asm memory constraint"); case InlineAsm::Constraint_i: case InlineAsm::Constraint_Q: + // Accept an address with a short displacement, but no index. + Form = SystemZAddressingMode::FormBD; + DispRange = SystemZAddressingMode::Disp12Only; + break; case InlineAsm::Constraint_R: - // Accept addresses with short displacements, which are compatible - // with Q and R. But keep the index operand for future expansion (e.g. the - // index for R). - if (selectBDXAddr(SystemZAddressingMode::FormBD, - SystemZAddressingMode::Disp12Only, - Op, Base, Disp, Index)) { - OutOps.push_back(Base); - OutOps.push_back(Disp); - OutOps.push_back(Index); - return false; - } + // Accept an address with a short displacement and an index. + Form = SystemZAddressingMode::FormBDXNormal; + DispRange = SystemZAddressingMode::Disp12Only; break; case InlineAsm::Constraint_S: + // Accept an address with a long displacement, but no index. + Form = SystemZAddressingMode::FormBD; + DispRange = SystemZAddressingMode::Disp20Only; + break; case InlineAsm::Constraint_T: case InlineAsm::Constraint_m: - // Accept addresses with long displacements. As above, keep the index for - // future implementation of index for the T constraint. - if (selectBDXAddr(SystemZAddressingMode::FormBD, - SystemZAddressingMode::Disp20Only, - Op, Base, Disp, Index)) { - OutOps.push_back(Base); - OutOps.push_back(Disp); - OutOps.push_back(Index); - return false; - } + // Accept an address with a long displacement and an index. + // m works the same as T, as this is the most general case. + Form = SystemZAddressingMode::FormBDXNormal; + DispRange = SystemZAddressingMode::Disp20Only; break; } + + if (selectBDXAddr(Form, DispRange, Op, Base, Disp, Index)) { + OutOps.push_back(Base); + OutOps.push_back(Disp); + OutOps.push_back(Index); + return false; + } + return true; } Index: test/CodeGen/SystemZ/asm-02.ll =================================================================== --- test/CodeGen/SystemZ/asm-02.ll +++ test/CodeGen/SystemZ/asm-02.ll @@ -48,5 +48,38 @@ ret void } -; FIXME: at the moment the precise constraint is not passed down to -; target code, so we must conservatively treat "R" as "Q". +; Check that indices are allowed +define void @f5(i64 %base, i64 %index) { +; CHECK-LABEL: f5: +; CHECK: blah 0(%r3,%r2) +; CHECK: br %r14 + %add = add i64 %base, %index + %addr = inttoptr i64 %add to i64 * + call void asm "blah $0", "=*R" (i64 *%addr) + ret void +} + +; Check that indices and displacements are allowed simultaneously +define void @f6(i64 %base, i64 %index) { +; CHECK-LABEL: f6: +; CHECK: blah 4095(%r3,%r2) +; CHECK: br %r14 + %add = add i64 %base, 4095 + %addi = add i64 %add, %index + %addr = inttoptr i64 %addi to i64 * + call void asm "blah $0", "=*R" (i64 *%addr) + ret void +} + +; Check that LAY is used if there is an index but the displacement is too large +define void @f7(i64 %base, i64 %index) { +; CHECK-LABEL: f7: +; CHECK: lay %r0, 4096(%r3,%r2) +; CHECK: blah 0(%r0) +; CHECK: br %r14 + %add = add i64 %base, 4096 + %addi = add i64 %add, %index + %addr = inttoptr i64 %addi to i64 * + call void asm "blah $0", "=*R" (i64 *%addr) + ret void +} Index: test/CodeGen/SystemZ/asm-04.ll =================================================================== --- test/CodeGen/SystemZ/asm-04.ll +++ test/CodeGen/SystemZ/asm-04.ll @@ -3,14 +3,71 @@ ; ; RUN: llc < %s -mtriple=s390x-linux-gnu -no-integrated-as | FileCheck %s +; Check the lowest range. define void @f1(i64 %base) { ; CHECK-LABEL: f1: +; CHECK: blah -524288(%r2) +; CHECK: br %r14 + %add = add i64 %base, -524288 + %addr = inttoptr i64 %add to i64 * + call void asm "blah $0", "=*T" (i64 *%addr) + ret void +} + +; Check the next lowest byte. +define void @f2(i64 %base) { +; CHECK-LABEL: f2: +; CHECK: agfi %r2, -524289 ; CHECK: blah 0(%r2) ; CHECK: br %r14 - %addr = inttoptr i64 %base to i64 * + %add = add i64 %base, -524289 + %addr = inttoptr i64 %add to i64 * call void asm "blah $0", "=*T" (i64 *%addr) ret void } -; FIXME: at the moment the precise constraint is not passed down to -; target code, so we must conservatively treat "T" as "S". +; Check the highest range. +define void @f3(i64 %base) { +; CHECK-LABEL: f3: +; CHECK: blah 524287(%r2) +; CHECK: br %r14 + %add = add i64 %base, 524287 + %addr = inttoptr i64 %add to i64 * + call void asm "blah $0", "=*T" (i64 *%addr) + ret void +} + +; Check the next highest byte. +define void @f4(i64 %base) { +; CHECK-LABEL: f4: +; CHECK: agfi %r2, 524288 +; CHECK: blah 0(%r2) +; CHECK: br %r14 + %add = add i64 %base, 524288 + %addr = inttoptr i64 %add to i64 * + call void asm "blah $0", "=*T" (i64 *%addr) + ret void +} + +; Check that indices are allowed +define void @f5(i64 %base, i64 %index) { +; CHECK-LABEL: f5: +; CHECK: blah 0(%r3,%r2) +; CHECK: br %r14 + %add = add i64 %base, %index + %addr = inttoptr i64 %add to i64 * + call void asm "blah $0", "=*T" (i64 *%addr) + ret void +} + +; Check that indices and displacements are allowed simultaneously +define void @f6(i64 %base, i64 %index) { +; CHECK-LABEL: f6: +; CHECK: blah 524287(%r3,%r2) +; CHECK: br %r14 + %add = add i64 %base, 524287 + %addi = add i64 %add, %index + %addr = inttoptr i64 %addi to i64 * + call void asm "blah $0", "=*T" (i64 *%addr) + ret void +} Index: test/CodeGen/SystemZ/asm-05.ll =================================================================== --- test/CodeGen/SystemZ/asm-05.ll +++ test/CodeGen/SystemZ/asm-05.ll @@ -10,6 +10,3 @@ call void asm "blah $0", "=*m" (i64 *%addr) ret void } - -; FIXME: at the moment the precise constraint is not passed down to -; target code, so we must conservatively treat "m" as "S".