Index: clang/lib/Basic/Targets/SystemZ.h =================================================================== --- clang/lib/Basic/Targets/SystemZ.h +++ clang/lib/Basic/Targets/SystemZ.h @@ -86,6 +86,20 @@ switch(Constraint[0]) { case 'p': // Keep 'p' constraint. return std::string("p"); + case 'Z': + switch (Constraint[1]) { + default: + break; + case 'Q': // Address with base and unsigned 12-bit displacement + case 'R': // Likewise, plus an index + case 'S': // Address with base and signed 20-bit displacement + case 'T': // Likewise, plus an index + // "^" hints llvm that this is a 2 letter constraint. + // "Constraint++" is used to promote the string iterator + // to the next constraint. + return std::string("^") + std::string(Constraint++, 2); + } + break; default: break; } return TargetInfo::convertConstraint(Constraint); Index: clang/lib/Basic/Targets/SystemZ.cpp =================================================================== --- clang/lib/Basic/Targets/SystemZ.cpp +++ clang/lib/Basic/Targets/SystemZ.cpp @@ -59,6 +59,17 @@ default: return false; + case 'Z': + switch (Name[1]) { + default: + return false; + case 'Q': // Address with base and unsigned 12-bit displacement + case 'R': // Likewise, plus an index + case 'S': // Address with base and signed 20-bit displacement + case 'T': // Likewise, plus an index + break; + } + LLVM_FALLTHROUGH; case 'p': // Address case 'a': // Address register case 'd': // Data register (equivalent to 'r') Index: clang/test/CodeGen/SystemZ/systemz-inline-asm-03.c =================================================================== --- clang/test/CodeGen/SystemZ/systemz-inline-asm-03.c +++ clang/test/CodeGen/SystemZ/systemz-inline-asm-03.c @@ -6,6 +6,34 @@ long Idx; unsigned long Addr; +unsigned long fun_BD12_Q() { +// CHECK-LABEL: define{{.*}} i64 @fun_BD12_Q() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZQ"(i64* nonnull %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZQ" (&A[100])); + return Addr; +} + +unsigned long fun_BD12_R() { +// CHECK-LABEL: define{{.*}} i64 @fun_BD12_R() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZR"(i64* nonnull %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZR" (&A[100])); + return Addr; +} + +unsigned long fun_BD12_S() { +// CHECK-LABEL: define{{.*}} i64 @fun_BD12_S() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZS"(i64* nonnull %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZS" (&A[100])); + return Addr; +} + +unsigned long fun_BD12_T() { +// CHECK-LABEL: define{{.*}} i64 @fun_BD12_T() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZT"(i64* nonnull %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZT" (&A[100])); + return Addr; +} + unsigned long fun_BD12_p() { // CHECK-LABEL: define{{.*}} i64 @fun_BD12_p() // CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* nonnull %arrayidx) @@ -13,6 +41,34 @@ return Addr; } +unsigned long fun_BDX12_Q() { +// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_Q() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZQ"(i64* %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZQ" (&A[Idx + 100])); + return Addr; +} + +unsigned long fun_BDX12_R() { +// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_R() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZR"(i64* %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZR" (&A[Idx + 100])); + return Addr; +} + +unsigned long fun_BDX12_S() { +// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_S() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZS"(i64* %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZS" (&A[Idx + 100])); + return Addr; +} + +unsigned long fun_BDX12_T() { +// CHECK-LABEL: define{{.*}} i64 @fun_BDX12_T() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZT"(i64* %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZT" (&A[Idx + 100])); + return Addr; +} + unsigned long fun_BDX12_p() { // CHECK-LABEL: define{{.*}} i64 @fun_BDX12_p() // CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* %arrayidx) @@ -20,6 +76,34 @@ return Addr; } +unsigned long fun_BD20_Q() { +// CHECK-LABEL: define{{.*}} i64 @fun_BD20_Q() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZQ"(i64* nonnull %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZQ" (&A[1000])); + return Addr; +} + +unsigned long fun_BD20_R() { +// CHECK-LABEL: define{{.*}} i64 @fun_BD20_R() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZR"(i64* nonnull %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZR" (&A[1000])); + return Addr; +} + +unsigned long fun_BD20_S() { +// CHECK-LABEL: define{{.*}} i64 @fun_BD20_S() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZS"(i64* nonnull %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZS" (&A[1000])); + return Addr; +} + +unsigned long fun_BD20_T() { +// CHECK-LABEL: define{{.*}} i64 @fun_BD20_T() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZT"(i64* nonnull %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZT" (&A[1000])); + return Addr; +} + unsigned long fun_BD20_p() { // CHECK-LABEL: define{{.*}} i64 @fun_BD20_p() // CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* nonnull %arrayidx) @@ -27,6 +111,34 @@ return Addr; } +unsigned long fun_BDX20_Q() { +// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_Q() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZQ"(i64* %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZQ" (&A[Idx + 1000])); + return Addr; +} + +unsigned long fun_BDX20_R() { +// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_R() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZR"(i64* %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZR" (&A[Idx + 1000])); + return Addr; +} + +unsigned long fun_BDX20_S() { +// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_S() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZS"(i64* %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZS" (&A[Idx + 1000])); + return Addr; +} + +unsigned long fun_BDX20_T() { +// CHECK-LABEL: define{{.*}} i64 @fun_BDX20_T() +// CHECK: call i64 asm "lay $0, $1", "=r,^ZT"(i64* %arrayidx) + asm("lay %0, %1" : "=r" (Addr) : "ZT" (&A[Idx + 1000])); + return Addr; +} + unsigned long fun_BDX20_p() { // CHECK-LABEL: define{{.*}} i64 @fun_BDX20_p() // CHECK: call i64 asm "lay $0, $1", "=r,p"(i64* %arrayidx) Index: llvm/include/llvm/IR/InlineAsm.h =================================================================== --- llvm/include/llvm/IR/InlineAsm.h +++ llvm/include/llvm/IR/InlineAsm.h @@ -274,8 +274,12 @@ // Address constraints Constraint_p, + Constraint_ZQ, + Constraint_ZR, + Constraint_ZS, + Constraint_ZT, - Constraints_Max = Constraint_p, + Constraints_Max = Constraint_ZT, Constraints_ShiftAmount = 16, Flag_MatchingOperand = 0x80000000 @@ -462,6 +466,14 @@ return "Zy"; case InlineAsm::Constraint_p: return "p"; + case InlineAsm::Constraint_ZQ: + return "ZQ"; + case InlineAsm::Constraint_ZR: + return "ZR"; + case InlineAsm::Constraint_ZS: + return "ZS"; + case InlineAsm::Constraint_ZT: + return "ZT"; default: llvm_unreachable("Unknown memory constraint"); } Index: llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ llvm/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -1683,16 +1683,19 @@ llvm_unreachable("Unexpected asm memory constraint"); case InlineAsm::Constraint_i: case InlineAsm::Constraint_Q: + case InlineAsm::Constraint_ZQ: // Accept an address with a short displacement, but no index. Form = SystemZAddressingMode::FormBD; DispRange = SystemZAddressingMode::Disp12Only; break; case InlineAsm::Constraint_R: + case InlineAsm::Constraint_ZR: // Accept an address with a short displacement and an index. Form = SystemZAddressingMode::FormBDXNormal; DispRange = SystemZAddressingMode::Disp12Only; break; case InlineAsm::Constraint_S: + case InlineAsm::Constraint_ZS: // Accept an address with a long displacement, but no index. Form = SystemZAddressingMode::FormBD; DispRange = SystemZAddressingMode::Disp20Only; @@ -1701,6 +1704,7 @@ case InlineAsm::Constraint_m: case InlineAsm::Constraint_o: case InlineAsm::Constraint_p: + case InlineAsm::Constraint_ZT: // Accept an address with a long displacement and an index. // m works the same as T, as this is the most general case. // We don't really have any special handling of "offsettable" Index: llvm/lib/Target/SystemZ/SystemZISelLowering.h =================================================================== --- llvm/lib/Target/SystemZ/SystemZISelLowering.h +++ llvm/lib/Target/SystemZ/SystemZISelLowering.h @@ -497,6 +497,19 @@ case 'T': return InlineAsm::Constraint_T; } + } else if (ConstraintCode.size() == 2 && ConstraintCode[0] == 'Z') { + switch (ConstraintCode[1]) { + default: + break; + case 'Q': + return InlineAsm::Constraint_ZQ; + case 'R': + return InlineAsm::Constraint_ZR; + case 'S': + return InlineAsm::Constraint_ZS; + case 'T': + return InlineAsm::Constraint_ZT; + } } return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); } Index: llvm/lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1034,6 +1034,17 @@ case 'M': // 0x7fffffff return C_Immediate; + default: + break; + } + } else if (Constraint.size() == 2 && Constraint[0] == 'Z') { + switch (Constraint[1]) { + case 'Q': // Address with base and unsigned 12-bit displacement + case 'R': // Likewise, plus an index + case 'S': // Address with base and signed 20-bit displacement + case 'T': // Likewise, plus an index + return C_Address; + default: break; } Index: llvm/test/CodeGen/SystemZ/inline-asm-addr.ll =================================================================== --- llvm/test/CodeGen/SystemZ/inline-asm-addr.ll +++ llvm/test/CodeGen/SystemZ/inline-asm-addr.ll @@ -4,6 +4,54 @@ @A = global i64* null, align 8 @Idx = global i64 0, align 8 +define i64 @fun_BD12_Q() { +; CHECK-LABEL: fun_BD12_Q: +; CHECK: #APP +; CHECK: lay %r2, 800(%r1) +entry: + %0 = load i64*, i64** @A + %arrayidx = getelementptr inbounds i64, i64* %0, i64 100 + %1 = tail call i64 asm "lay $0, $1", "=r,^ZQ"(i64* nonnull %arrayidx) + store i64 %1, i64* @Addr + ret i64 %1 +} + +define i64 @fun_BD12_R() { +; CHECK-LABEL: fun_BD12_R: +; CHECK: #APP +; CHECK: lay %r2, 800(%r1) +entry: + %0 = load i64*, i64** @A + %arrayidx = getelementptr inbounds i64, i64* %0, i64 100 + %1 = tail call i64 asm "lay $0, $1", "=r,^ZR"(i64* nonnull %arrayidx) + store i64 %1, i64* @Addr + ret i64 %1 +} + +define i64 @fun_BD12_S() { +; CHECK-LABEL: fun_BD12_S: +; CHECK: #APP +; CHECK: lay %r2, 800(%r1) +entry: + %0 = load i64*, i64** @A + %arrayidx = getelementptr inbounds i64, i64* %0, i64 100 + %1 = tail call i64 asm "lay $0, $1", "=r,^ZS"(i64* nonnull %arrayidx) + store i64 %1, i64* @Addr + ret i64 %1 +} + +define i64 @fun_BD12_T() { +; CHECK-LABEL: fun_BD12_T: +; CHECK: #APP +; CHECK: lay %r2, 800(%r1) +entry: + %0 = load i64*, i64** @A + %arrayidx = getelementptr inbounds i64, i64* %0, i64 100 + %1 = tail call i64 asm "lay $0, $1", "=r,^ZT"(i64* nonnull %arrayidx) + store i64 %1, i64* @Addr + ret i64 %1 +} + define i64 @fun_BD12_p() { ; CHECK-LABEL: fun_BD12_p: ; CHECK: #APP @@ -16,6 +64,62 @@ ret i64 %1 } +define i64 @fun_BDX12_Q() { +; CHECK-LABEL: fun_BDX12_Q: +; CHECK: #APP +; CHECK: lay %r2, 800(%r2) +entry: + %0 = load i64*, i64** @A + %1 = load i64, i64* @Idx + %add = add nsw i64 %1, 100 + %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add + %2 = tail call i64 asm "lay $0, $1", "=r,^ZQ"(i64* %arrayidx) + store i64 %2, i64* @Addr + ret i64 %2 +} + +define i64 @fun_BDX12_R() { +; CHECK-LABEL: fun_BDX12_R: +; CHECK: #APP +; CHECK: lay %r2, 800(%r1,%r2) +entry: + %0 = load i64*, i64** @A + %1 = load i64, i64* @Idx + %add = add nsw i64 %1, 100 + %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add + %2 = tail call i64 asm "lay $0, $1", "=r,^ZR"(i64* %arrayidx) + store i64 %2, i64* @Addr + ret i64 %2 +} + +define i64 @fun_BDX12_S() { +; CHECK-LABEL: fun_BDX12_S: +; CHECK: #APP +; CHECK: lay %r2, 800(%r2) +entry: + %0 = load i64*, i64** @A + %1 = load i64, i64* @Idx + %add = add nsw i64 %1, 100 + %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add + %2 = tail call i64 asm "lay $0, $1", "=r,^ZS"(i64* %arrayidx) + store i64 %2, i64* @Addr + ret i64 %2 +} + +define i64 @fun_BDX12_T() { +; CHECK-LABEL: fun_BDX12_T: +; CHECK: #APP +; CHECK: lay %r2, 800(%r1,%r2) +entry: + %0 = load i64*, i64** @A + %1 = load i64, i64* @Idx + %add = add nsw i64 %1, 100 + %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add + %2 = tail call i64 asm "lay $0, $1", "=r,^ZT"(i64* %arrayidx) + store i64 %2, i64* @Addr + ret i64 %2 +} + define i64 @fun_BDX12_p() { ; CHECK-LABEL: fun_BDX12_p: ; CHECK: #APP @@ -30,6 +134,54 @@ ret i64 %2 } +define i64 @fun_BD20_Q() { +; CHECK-LABEL: fun_BD20_Q: +; CHECK: #APP +; CHECK: lay %r2, 0(%r2) +entry: + %0 = load i64*, i64** @A + %arrayidx = getelementptr inbounds i64, i64* %0, i64 1000 + %1 = tail call i64 asm "lay $0, $1", "=r,^ZQ"(i64* nonnull %arrayidx) + store i64 %1, i64* @Addr + ret i64 %1 +} + +define i64 @fun_BD20_R() { +; CHECK-LABEL: fun_BD20_R: +; CHECK: #APP +; CHECK: lay %r2, 0(%r2) +entry: + %0 = load i64*, i64** @A + %arrayidx = getelementptr inbounds i64, i64* %0, i64 1000 + %1 = tail call i64 asm "lay $0, $1", "=r,^ZR"(i64* nonnull %arrayidx) + store i64 %1, i64* @Addr + ret i64 %1 +} + +define i64 @fun_BD20_S() { +; CHECK-LABEL: fun_BD20_S: +; CHECK: #APP +; CHECK: lay %r2, 8000(%r1) +entry: + %0 = load i64*, i64** @A + %arrayidx = getelementptr inbounds i64, i64* %0, i64 1000 + %1 = tail call i64 asm "lay $0, $1", "=r,^ZS"(i64* nonnull %arrayidx) + store i64 %1, i64* @Addr + ret i64 %1 +} + +define i64 @fun_BD20_T() { +; CHECK-LABEL: fun_BD20_T: +; CHECK: #APP +; CHECK: lay %r2, 8000(%r1) +entry: + %0 = load i64*, i64** @A + %arrayidx = getelementptr inbounds i64, i64* %0, i64 1000 + %1 = tail call i64 asm "lay $0, $1", "=r,^ZT"(i64* nonnull %arrayidx) + store i64 %1, i64* @Addr + ret i64 %1 +} + define i64 @fun_BD20_p() { ; CHECK-LABEL: fun_BD20_p: ; CHECK: #APP @@ -42,6 +194,62 @@ ret i64 %1 } +define i64 @fun_BDX20_Q() { +; CHECK-LABEL: fun_BDX20_Q: +; CHECK: #APP +; CHECK: lay %r2, 0(%r1) +entry: + %0 = load i64*, i64** @A + %1 = load i64, i64* @Idx + %add = add nsw i64 %1, 1000 + %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add + %2 = tail call i64 asm "lay $0, $1", "=r,^ZQ"(i64* %arrayidx) + store i64 %2, i64* @Addr + ret i64 %2 +} + +define i64 @fun_BDX20_R() { +; CHECK-LABEL: fun_BDX20_R: +; CHECK: #APP +; CHECK: lay %r2, 0(%r1) +entry: + %0 = load i64*, i64** @A + %1 = load i64, i64* @Idx + %add = add nsw i64 %1, 1000 + %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add + %2 = tail call i64 asm "lay $0, $1", "=r,^ZR"(i64* %arrayidx) + store i64 %2, i64* @Addr + ret i64 %2 +} + +define i64 @fun_BDX20_S() { +; CHECK-LABEL: fun_BDX20_S: +; CHECK: #APP +; CHECK: lay %r2, 8000(%r2) +entry: + %0 = load i64*, i64** @A + %1 = load i64, i64* @Idx + %add = add nsw i64 %1, 1000 + %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add + %2 = tail call i64 asm "lay $0, $1", "=r,^ZS"(i64* %arrayidx) + store i64 %2, i64* @Addr + ret i64 %2 +} + +define i64 @fun_BDX20_T() { +; CHECK-LABEL: fun_BDX20_T: +; CHECK: #APP +; CHECK: lay %r2, 8000(%r1,%r2) +entry: + %0 = load i64*, i64** @A + %1 = load i64, i64* @Idx + %add = add nsw i64 %1, 1000 + %arrayidx = getelementptr inbounds i64, i64* %0, i64 %add + %2 = tail call i64 asm "lay $0, $1", "=r,^ZT"(i64* %arrayidx) + store i64 %2, i64* @Addr + ret i64 %2 +} + define i64 @fun_BDX20_p() { ; CHECK-LABEL: fun_BDX20_p: ; CHECK: #APP