Index: include/llvm/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -284,6 +284,12 @@ // the assembly matcher will provide a function to map from diagnostic types // to message strings. string DiagnosticString = ""; + + // When referenced in the result of a CodeGen pattern, GlobalISel will + // normally copy the matched operand to the result. When this is set, it will + // emit a special copy that will replace zero-immediates with the specified + // zero-register. + Register GIZeroRegister = ?; } // The memberList in a RegisterClass is a dag of set operations. TableGen Index: lib/Target/AArch64/AArch64InstrFormats.td =================================================================== --- lib/Target/AArch64/AArch64InstrFormats.td +++ lib/Target/AArch64/AArch64InstrFormats.td @@ -2603,23 +2603,6 @@ (!cast(NAME # "ui") regtype:$Rt, GPR64sp:$Rn, 0)>; } -// Same as StoreUI, but take a RegisterOperand. This is used by GlobalISel to -// substitute zero-registers automatically. -// -// TODO: Roll out zero-register subtitution to GPR32/GPR64 and fold this back -// into StoreUI. -multiclass StoreUIz sz, bit V, bits<2> opc, RegisterOperand regtype, - Operand indextype, string asm, list pattern> { - let AddedComplexity = 10, mayLoad = 0, mayStore = 1, hasSideEffects = 0 in - def ui : BaseLoadStoreUI, - Sched<[WriteST]>; - - def : InstAlias(NAME # "ui") regtype:$Rt, GPR64sp:$Rn, 0)>; -} - def PrefetchOperand : AsmOperandClass { let Name = "Prefetch"; let ParserMethod = "tryParsePrefetch"; Index: lib/Target/AArch64/AArch64InstrInfo.td =================================================================== --- lib/Target/AArch64/AArch64InstrInfo.td +++ lib/Target/AArch64/AArch64InstrInfo.td @@ -2249,11 +2249,11 @@ //--- // (unsigned immediate) -defm STRX : StoreUIz<0b11, 0, 0b00, GPR64z, uimm12s8, "str", - [(store GPR64z:$Rt, +defm STRX : StoreUI<0b11, 0, 0b00, GPR64, uimm12s8, "str", + [(store GPR64:$Rt, (am_indexed64 GPR64sp:$Rn, uimm12s8:$offset))]>; -defm STRW : StoreUIz<0b10, 0, 0b00, GPR32z, uimm12s4, "str", - [(store GPR32z:$Rt, +defm STRW : StoreUI<0b10, 0, 0b00, GPR32, uimm12s4, "str", + [(store GPR32:$Rt, (am_indexed32 GPR64sp:$Rn, uimm12s4:$offset))]>; defm STRB : StoreUI<0b00, 1, 0b00, FPR8, uimm12s1, "str", [(store FPR8:$Rt, @@ -2269,12 +2269,12 @@ (am_indexed64 GPR64sp:$Rn, uimm12s8:$offset))]>; defm STRQ : StoreUI<0b00, 1, 0b10, FPR128, uimm12s16, "str", []>; -defm STRHH : StoreUIz<0b01, 0, 0b00, GPR32z, uimm12s2, "strh", - [(truncstorei16 GPR32z:$Rt, +defm STRHH : StoreUI<0b01, 0, 0b00, GPR32, uimm12s2, "strh", + [(truncstorei16 GPR32:$Rt, (am_indexed16 GPR64sp:$Rn, uimm12s2:$offset))]>; -defm STRBB : StoreUIz<0b00, 0, 0b00, GPR32z, uimm12s1, "strb", - [(truncstorei8 GPR32z:$Rt, +defm STRBB : StoreUI<0b00, 0, 0b00, GPR32, uimm12s1, "strb", + [(truncstorei8 GPR32:$Rt, (am_indexed8 GPR64sp:$Rn, uimm12s1:$offset))]>; Index: lib/Target/AArch64/AArch64RegisterInfo.td =================================================================== --- lib/Target/AArch64/AArch64RegisterInfo.td +++ lib/Target/AArch64/AArch64RegisterInfo.td @@ -140,10 +140,12 @@ def GPR32 : RegisterClass<"AArch64", [i32], 32, (add GPR32common, WZR)> { let AltOrders = [(rotl GPR32, 8)]; let AltOrderSelect = [{ return 1; }]; + let GIZeroRegister = WZR; } def GPR64 : RegisterClass<"AArch64", [i64], 64, (add GPR64common, XZR)> { let AltOrders = [(rotl GPR64, 8)]; let AltOrderSelect = [{ return 1; }]; + let GIZeroRegister = XZR; } // GPR register classes which include SP/WSP. @@ -169,20 +171,15 @@ let ParserMatchClass = GPR64spPlus0Operand; } -// GPR32/GPR64 but with zero-register substitution enabled. -// TODO: Roll this out to GPR32/GPR64/GPR32all/GPR64all. -def GPR32z : RegisterOperand { +// GPR register classes which include WZR/XZR AND SP/WSP. This is not a +// constraint used by any instructions, it is used as a common super-class. +def GPR32all : RegisterClass<"AArch64", [i32], 32, (add GPR32common, WZR, WSP)> { let GIZeroRegister = WZR; } -def GPR64z : RegisterOperand { +def GPR64all : RegisterClass<"AArch64", [i64], 64, (add GPR64common, XZR, SP)> { let GIZeroRegister = XZR; } -// GPR register classes which include WZR/XZR AND SP/WSP. This is not a -// constraint used by any instructions, it is used as a common super-class. -def GPR32all : RegisterClass<"AArch64", [i32], 32, (add GPR32common, WZR, WSP)>; -def GPR64all : RegisterClass<"AArch64", [i64], 64, (add GPR64common, XZR, SP)>; - // For tail calls, we can't use callee-saved registers, as they are restored // to the saved value before the tail call, which would clobber a call address. // This is for indirect tail calls to store the address of the destination. Index: utils/TableGen/GlobalISelEmitter.cpp =================================================================== --- utils/TableGen/GlobalISelEmitter.cpp +++ utils/TableGen/GlobalISelEmitter.cpp @@ -2597,16 +2597,18 @@ return Error::success(); } + if ((ChildRec->isSubClassOf("RegisterClass") || + ChildRec->isSubClassOf("RegisterOperand")) && + !ChildRec->isValueUnset("GIZeroRegister")) { + DstMIBuilder.addRenderer( + 0, InsnMatcher, DstChild->getName(), + ChildRec->getValueAsDef("GIZeroRegister")); + return Error::success(); + } + if (ChildRec->isSubClassOf("RegisterClass") || ChildRec->isSubClassOf("RegisterOperand") || ChildRec->isSubClassOf("ValueType")) { - if (ChildRec->isSubClassOf("RegisterOperand") && - !ChildRec->isValueUnset("GIZeroRegister")) { - DstMIBuilder.addRenderer( - 0, InsnMatcher, DstChild->getName(), - ChildRec->getValueAsDef("GIZeroRegister")); - return Error::success(); - } DstMIBuilder.addRenderer(0, InsnMatcher, DstChild->getName());