Skip to content

[X86] Support EGPR for inline assembly. #92338

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -6281,6 +6281,8 @@ def mno_apx_features_EQ : CommaJoined<["-"], "mno-apx-features=">, Group<m_x86_F
// we will add it to -mapxf.
def mapxf : Flag<["-"], "mapxf">, Alias<mapx_features_EQ>, AliasArgs<["egpr","push2pop2","ppx", "ndd"]>;
def mno_apxf : Flag<["-"], "mno-apxf">, Alias<mno_apx_features_EQ>, AliasArgs<["egpr","push2pop2","ppx","ndd"]>;
def mapx_inline_asm_use_gpr32 : Flag<["-"], "mapx-inline-asm-use-gpr32">, Group<m_Group>,
HelpText<"Enable use of GPR32 in inline assembly for APX">;
} // let Flags = [TargetSpecific]

// VE feature flags
Expand Down
26 changes: 26 additions & 0 deletions clang/lib/Basic/Targets/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,8 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
HasFullBFloat16 = true;
} else if (Feature == "+egpr") {
HasEGPR = true;
} else if (Feature == "+inline-asm-use-gpr32") {
HasInlineAsmUseGPR32 = true;
} else if (Feature == "+push2pop2") {
HasPush2Pop2 = true;
} else if (Feature == "+ppx") {
Expand Down Expand Up @@ -974,6 +976,8 @@ void X86TargetInfo::getTargetDefines(const LangOptions &Opts,
// Condition here is aligned with the feature set of mapxf in Options.td
if (HasEGPR && HasPush2Pop2 && HasPPX && HasNDD)
Builder.defineMacro("__APX_F__");
if (HasEGPR && HasInlineAsmUseGPR32)
Builder.defineMacro("__APX_INLINE_ASM_USE_GPR32__");

// Each case falls through to the previous one here.
switch (SSELevel) {
Expand Down Expand Up @@ -1493,6 +1497,15 @@ bool X86TargetInfo::validateAsmConstraint(
case 'C': // SSE floating point constant.
case 'G': // x87 floating point constant.
return true;
case 'j':
Name++;
switch (*Name) {
default:
return false;
case 'R':
Info.setAllowsRegister();
return true;
}
case '@':
// CC condition changes.
if (auto Len = matchAsmCCConstraint(Name)) {
Expand Down Expand Up @@ -1764,6 +1777,19 @@ std::string X86TargetInfo::convertConstraint(const char *&Constraint) const {
// to the next constraint.
return std::string("^") + std::string(Constraint++, 2);
}
case 'j':
switch (Constraint[1]) {
default:
// Break from inner switch and fall through (copy single char),
// continue parsing after copying the current constraint into
// the return string.
break;
case 'R':
// "^" 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);
}
[[fallthrough]];
default:
return std::string(1, *Constraint);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/Targets/X86.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class LLVM_LIBRARY_VISIBILITY X86TargetInfo : public TargetInfo {
bool HasNDD = false;
bool HasCCMP = false;
bool HasCF = false;
bool HasInlineAsmUseGPR32 = false;

protected:
llvm::X86::CPUKind CPU = llvm::X86::CK_None;
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Driver/ToolChains/Arch/X86.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,6 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("+prefer-no-gather");
if (Args.hasArg(options::OPT_mno_scatter))
Features.push_back("+prefer-no-scatter");
if (Args.hasArg(options::OPT_mapx_inline_asm_use_gpr32))
Features.push_back("+inline-asm-use-gpr32");
}
3 changes: 3 additions & 0 deletions clang/test/Driver/x86-apx-inline-asm-use-gpr32.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/// Tests -mapx-inline-asm-use-gpr32
// RUN: %clang -target x86_64-unknown-linux-gnu -c -mapx-inline-asm-use-gpr32 -### %s 2>&1 | FileCheck --check-prefix=GPR32 %s
// GPR32: "-target-feature" "+inline-asm-use-gpr32"
5 changes: 5 additions & 0 deletions clang/test/Preprocessor/x86_target_features.c
Original file line number Diff line number Diff line change
Expand Up @@ -811,3 +811,8 @@
// NDD: #define __NDD__ 1
// PPX: #define __PPX__ 1
// PUSH2POP2: #define __PUSH2POP2__ 1

// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-inline-asm-use-gpr32 -x c -E -dM -o - %s | FileCheck --check-prefixes=NOUSEGPR32 %s
// RUN: %clang -target x86_64-unknown-unknown -march=x86-64 -mapx-features=egpr -mapx-inline-asm-use-gpr32 -x c -E -dM -o - %s | FileCheck --check-prefixes=USEGPR32 %s
// NOUSEGPR32-NOT: #define __APX_INLINE_ASM_USE_GPR32__ 1
// USEGPR32: #define __APX_INLINE_ASM_USE_GPR32__ 1
2 changes: 2 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5414,6 +5414,8 @@ X86:
operand will get allocated only to RAX -- if two 32-bit operands are needed,
you're better off splitting it yourself, before passing it to the asm
statement.
- ``jR``: An 8, 16, 32, or 64-bit integer EGPR when EGPR feature is on.
Otherwise, same as ``R``.

XCore:

Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/X86/X86.td
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ def FeatureCCMP : SubtargetFeature<"ccmp", "HasCCMP", "true",
"Support conditional cmp & test instructions">;
def FeatureCF : SubtargetFeature<"cf", "HasCF", "true",
"Support conditional faulting">;
def FeatureUseGPR32InInlineAsm
: SubtargetFeature<"inline-asm-use-gpr32", "UseInlineAsmGPR32", "false",
"Enable use of GPR32 in inline assembly for APX">;

// Ivy Bridge and newer processors have enhanced REP MOVSB and STOSB (aka
// "string operations"). See "REP String Enhancement" in the Intel Software
Expand Down
55 changes: 51 additions & 4 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57574,6 +57574,13 @@ X86TargetLowering::getConstraintType(StringRef Constraint) const {
case '2':
return C_RegisterClass;
}
case 'j':
switch (Constraint[1]) {
default:
break;
case 'R':
return C_RegisterClass;
}
}
} else if (parseConstraintCode(Constraint) != X86::COND_INVALID)
return C_Other;
Expand Down Expand Up @@ -57653,6 +57660,18 @@ X86TargetLowering::getSingleConstraintMatchWeight(
break;
}
break;
case 'j':
if (StringRef(Constraint).size() != 2)
break;
switch (Constraint[1]) {
default:
return CW_Invalid;
case 'R':
if (CallOperandVal->getType()->isIntegerTy())
Wt = CW_SpecificReg;
break;
}
break;
case 'v':
if ((Ty->getPrimitiveSizeInBits() == 512) && Subtarget.hasAVX512())
Wt = CW_Register;
Expand Down Expand Up @@ -58016,15 +58035,27 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
break;
case 'r': // GENERAL_REGS
case 'l': // INDEX_REGS
if (Subtarget.useInlineAsmGPR32()) {
if (VT == MVT::i8 || VT == MVT::i1)
return std::make_pair(0U, &X86::GR8_NOREX2RegClass);
if (VT == MVT::i16)
return std::make_pair(0U, &X86::GR16_NOREX2RegClass);
if (VT == MVT::i32 || VT == MVT::f32 ||
(!VT.isVector() && !Subtarget.is64Bit()))
return std::make_pair(0U, &X86::GR32_NOREX2RegClass);
if (VT != MVT::f80 && !VT.isVector())
return std::make_pair(0U, &X86::GR64_NOREX2RegClass);
break;
}
if (VT == MVT::i8 || VT == MVT::i1)
return std::make_pair(0U, &X86::GR8_NOREX2RegClass);
return std::make_pair(0U, &X86::GR8RegClass);
if (VT == MVT::i16)
return std::make_pair(0U, &X86::GR16_NOREX2RegClass);
return std::make_pair(0U, &X86::GR16RegClass);
if (VT == MVT::i32 || VT == MVT::f32 ||
(!VT.isVector() && !Subtarget.is64Bit()))
return std::make_pair(0U, &X86::GR32_NOREX2RegClass);
return std::make_pair(0U, &X86::GR32RegClass);
if (VT != MVT::f80 && !VT.isVector())
return std::make_pair(0U, &X86::GR64_NOREX2RegClass);
return std::make_pair(0U, &X86::GR64RegClass);
break;
case 'R': // LEGACY_REGS
if (VT == MVT::i8 || VT == MVT::i1)
Expand Down Expand Up @@ -58248,6 +58279,22 @@ X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
}
break;
}
} else if (Constraint.size() == 2 && Constraint[0] == 'j') {
switch (Constraint[1]) {
default:
break;
case 'R':
if (VT == MVT::i8 || VT == MVT::i1)
return std::make_pair(0U, &X86::GR8RegClass);
if (VT == MVT::i16)
return std::make_pair(0U, &X86::GR16RegClass);
if (VT == MVT::i32 || VT == MVT::f32 ||
(!VT.isVector() && !Subtarget.is64Bit()))
return std::make_pair(0U, &X86::GR32RegClass);
if (VT != MVT::f80 && !VT.isVector())
return std::make_pair(0U, &X86::GR64RegClass);
break;
}
}

if (parseConstraintCode(Constraint) != X86::COND_INVALID)
Expand Down
19 changes: 19 additions & 0 deletions llvm/test/CodeGen/X86/apx/inline-asm-jR-constraint.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: not llc -mtriple=x86_64 %s 2>&1 | FileCheck %s --check-prefix=ERR
; RUN: llc -mtriple=x86_64 -mattr=+egpr < %s | FileCheck %s --check-prefix=EGPR
; RUN: llc -mtriple=x86_64 -mattr=+egpr,+inline-asm-use-gpr32 < %s | FileCheck %s --check-prefix=EGPRUSEGPR32

; ERR: error: inline assembly requires more registers than available

define void @constraint_jR_test() nounwind "frame-pointer"="all" {
; EGPR-LABEL: constraint_jR_test:
; EGPR: addq %r16, %rax
;
; EGPRUSEGPR32-LABEL: constraint_jR_test:
; EGPRUSEGPR32: addq %r16, %rax
entry:
%reg = alloca i64, align 8
%0 = load i64, ptr %reg, align 8
call void asm sideeffect "add $0, %rax", "^jR,~{rax},~{rbx},~{rcx},~{rdx},~{rdi},~{rsi},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{dirflag},~{fpsr},~{flags}"(i64 %0)
ret void
}
29 changes: 29 additions & 0 deletions llvm/test/CodeGen/X86/apx/inline-asm-r-constraint.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: not llc -mtriple=x86_64 < %s 2>&1 | FileCheck %s --check-prefix=ERR
; RUN: not llc -mtriple=x86_64 -mattr=+egpr < %s 2>&1 | FileCheck %s --check-prefix=ERR
; RUN: llc -mtriple=x86_64 -mattr=+egpr,+inline-asm-use-gpr32 < %s | FileCheck %s --check-prefix=USEGPR32

; ERR: error: inline assembly requires more registers than available

define void @constraint_r_test() nounwind "frame-pointer"="all" {
; USEGPR32-LABEL: constraint_r_test:
; USEGPR32: addq %r16, %rax
entry:
%reg = alloca i64, align 8
%0 = load i64, ptr %reg, align 8
call void asm sideeffect "add $0, %rax", "r,~{rax},~{rbx},~{rcx},~{rdx},~{rdi},~{rsi},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{dirflag},~{fpsr},~{flags}"(i64 %0)
ret void
}

define void @constraint_jR_test() nounwind "frame-pointer"="all" {
; EGPR-LABEL: constraint_jR_test:
; EGPR: addq %r16, %rax
;
; EGPRUSEGPR32-LABEL: constraint_jR_test:
; EGPRUSEGPR32: addq %r16, %rax
entry:
%reg = alloca i64, align 8
%0 = load i64, ptr %reg, align 8
call void asm sideeffect "add $0, %rax", "^jR,~{rax},~{rbx},~{rcx},~{rdx},~{rdi},~{rsi},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{dirflag},~{fpsr},~{flags}"(i64 %0)
ret void
}
Loading