Skip to content

Commit 16897c2

Browse files
[WebAssembly][GlobalISel] Migrate to extended LLT (llvm#193047)
Moves Wasm GISel to use the the new extended LLTs added by llvm#155107. Extended LLTs have (optional) information about whether a particular scalar is integer vs floating-point. This is a big win for Wasm, since we can avoid a lot of guess work, and map LLT i32, i64, f32, and f64 directly to their Wasm counterparts. To take full advantage of this, RegBankSelect has been automated, iterating over all operands and mapping typed LLTs to their appropriate register bank.
1 parent 8a9877d commit 16897c2

23 files changed

Lines changed: 822 additions & 871 deletions

llvm/lib/Target/WebAssembly/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ tablegen(LLVM WebAssemblyGenSDNodeInfo.inc -gen-sd-node-info)
1515
tablegen(LLVM WebAssemblyGenSubtargetInfo.inc -gen-subtarget)
1616

1717
set(LLVM_TARGET_DEFINITIONS WebAssemblyGISel.td)
18-
tablegen(LLVM WebAssemblyGenGlobalISel.inc -gen-global-isel)
18+
tablegen(LLVM WebAssemblyGenGlobalISel.inc -gen-global-isel -gisel-extended-llt)
1919
tablegen(LLVM WebAssemblyGenPreLegalizeGICombiner.inc -gen-global-isel-combiner
2020
-combiners="WebAssemblyPreLegalizerCombiner")
2121
tablegen(LLVM WebAssemblyGenPostLegalizeGICombiner.inc -gen-global-isel-combiner

llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,49 +25,52 @@ WebAssemblyLegalizerInfo::WebAssemblyLegalizerInfo(
2525
const WebAssemblySubtarget &ST) {
2626
using namespace TargetOpcode;
2727

28+
const LLT i32 = LLT::integer(32);
29+
const LLT i64 = LLT::integer(64);
30+
2831
const LLT s32 = LLT::scalar(32);
2932
const LLT s64 = LLT::scalar(64);
3033

3134
getActionDefinitionsBuilder({G_CONSTANT, G_IMPLICIT_DEF, G_ADD, G_SUB, G_MUL,
3235
G_UDIV, G_SDIV, G_UREM, G_SREM, G_AND, G_OR,
3336
G_XOR})
34-
.legalFor({s32, s64})
37+
.legalFor({i32, i64})
3538
.widenScalarToNextPow2(0)
3639
.clampScalar(0, s32, s64);
3740

3841
getActionDefinitionsBuilder({G_ASHR, G_LSHR, G_SHL})
39-
.legalFor({{s32, s32}, {s64, s64}})
42+
.legalFor({{i32, i32}, {i64, i64}})
4043
.widenScalarToNextPow2(0)
4144
.clampScalar(0, s32, s64)
4245
.scalarSameSizeAs(1, 0);
4346

4447
getActionDefinitionsBuilder({G_CTLZ, G_CTTZ, G_CTPOP})
45-
.legalFor({{s32, s32}, {s64, s64}})
48+
.legalFor({{i32, i32}, {i64, i64}})
4649
.widenScalarToNextPow2(1)
4750
.clampScalar(1, s32, s64)
4851
.scalarSameSizeAs(0, 1);
4952

5053
getActionDefinitionsBuilder({G_CTLZ_ZERO_UNDEF, G_CTTZ_ZERO_UNDEF}).lower();
5154

5255
getActionDefinitionsBuilder({G_ROTL, G_ROTR})
53-
.legalFor({{s32, s32}, {s64, s64}})
56+
.legalFor({{i32, i32}, {i64, i64}})
5457
.scalarSameSizeAs(1, 0)
5558
.lower();
5659

5760
getActionDefinitionsBuilder({G_FSHL, G_FSHR}).lower();
5861

5962
getActionDefinitionsBuilder({G_ANYEXT, G_SEXT, G_ZEXT})
60-
.legalFor({{s64, s32}})
63+
.legalFor({{i64, i32}})
6164
.clampScalar(0, s64, s64)
6265
.clampScalar(1, s32, s32);
6366

6467
getActionDefinitionsBuilder(G_TRUNC)
65-
.legalFor({{s32, s64}})
68+
.legalFor({{i32, i64}})
6669
.clampScalar(0, s32, s32)
6770
.clampScalar(1, s64, s64);
6871

6972
getActionDefinitionsBuilder(G_SEXT_INREG)
70-
.customFor(ST.hasSignExt(), {s32, s64})
73+
.customFor(ST.hasSignExt(), {i32, i64})
7174
.clampScalar(0, s32, s64)
7275
.lower();
7376

llvm/lib/Target/WebAssembly/GISel/WebAssemblyRegisterBankInfo.cpp

Lines changed: 44 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -31,29 +31,9 @@ enum PartialMappingIdx {
3131
PMI_Min = PMI_I32,
3232
};
3333

34-
enum ValueMappingIdx {
35-
InvalidIdx = 0,
36-
I32Idx = 1,
37-
I64Idx = 5,
38-
};
39-
4034
const RegisterBankInfo::PartialMapping PartMappings[]{{0, 32, I32RegBank},
4135
{0, 64, I64RegBank}};
4236

43-
const RegisterBankInfo::ValueMapping ValueMappings[] = {
44-
// invalid
45-
{nullptr, 0},
46-
// up to 4 operands as I32
47-
{&PartMappings[PMI_I32 - PMI_Min], 1},
48-
{&PartMappings[PMI_I32 - PMI_Min], 1},
49-
{&PartMappings[PMI_I32 - PMI_Min], 1},
50-
{&PartMappings[PMI_I32 - PMI_Min], 1},
51-
// up to 4 operands as I64
52-
{&PartMappings[PMI_I64 - PMI_Min], 1},
53-
{&PartMappings[PMI_I64 - PMI_Min], 1},
54-
{&PartMappings[PMI_I64 - PMI_Min], 1},
55-
{&PartMappings[PMI_I64 - PMI_Min], 1},
56-
};
5737
} // namespace WebAssembly
5838
} // namespace llvm
5939

@@ -67,8 +47,6 @@ WebAssemblyRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
6747
unsigned Opc = MI.getOpcode();
6848
const MachineFunction &MF = *MI.getParent()->getParent();
6949
const MachineRegisterInfo &MRI = MF.getRegInfo();
70-
const WebAssemblySubtarget &STI = MF.getSubtarget<WebAssemblySubtarget>();
71-
const WebAssemblyRegisterInfo &TRI = *STI.getRegisterInfo();
7250

7351
if ((Opc != TargetOpcode::COPY && !isPreISelGenericOpcode(Opc)) ||
7452
Opc == TargetOpcode::G_PHI) {
@@ -78,93 +56,54 @@ WebAssemblyRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const {
7856
return Mapping;
7957
}
8058

81-
const unsigned NumOperands = MI.getNumOperands();
82-
const ValueMapping *OperandsMapping = nullptr;
59+
const unsigned NumOperands = MI.isCopyLike() ? 1 : MI.getNumOperands();
8360
unsigned MappingID = DefaultMappingID;
8461

85-
const LLT Op0Ty = MRI.getType(MI.getOperand(0).getReg());
86-
unsigned Op0Size = Op0Ty.getSizeInBits();
87-
88-
auto &Op0IntValueMapping =
89-
WebAssembly::ValueMappings[Op0Size == 64 ? WebAssembly::I64Idx
90-
: WebAssembly::I32Idx];
91-
92-
using namespace TargetOpcode;
93-
switch (Opc) {
94-
case G_CONSTANT:
95-
OperandsMapping = getOperandsMapping({&Op0IntValueMapping, nullptr});
96-
break;
97-
case G_IMPLICIT_DEF:
98-
OperandsMapping = &Op0IntValueMapping;
99-
break;
100-
case G_ADD:
101-
case G_SUB:
102-
case G_MUL:
103-
case G_UDIV:
104-
case G_SDIV:
105-
case G_UREM:
106-
case G_SREM:
107-
case G_AND:
108-
case G_OR:
109-
case G_XOR:
110-
case G_ASHR:
111-
case G_LSHR:
112-
case G_SHL:
113-
case G_CTLZ:
114-
case G_CTLZ_ZERO_UNDEF:
115-
case G_CTTZ:
116-
case G_CTTZ_ZERO_UNDEF:
117-
case G_CTPOP:
118-
case G_ROTL:
119-
case G_ROTR:
120-
OperandsMapping = &Op0IntValueMapping;
121-
break;
122-
case G_ZEXT:
123-
case G_ANYEXT:
124-
case G_SEXT:
125-
case G_TRUNC: {
126-
const LLT Op1Ty = MRI.getType(MI.getOperand(1).getReg());
127-
unsigned Op1Size = Op1Ty.getSizeInBits();
128-
129-
auto &Op1IntValueMapping =
130-
WebAssembly::ValueMappings[Op1Size == 64 ? WebAssembly::I64Idx
131-
: WebAssembly::I32Idx];
132-
OperandsMapping =
133-
getOperandsMapping({&Op0IntValueMapping, &Op1IntValueMapping});
134-
break;
135-
}
136-
case G_SEXT_INREG:
137-
OperandsMapping =
138-
getOperandsMapping({&Op0IntValueMapping, &Op0IntValueMapping, nullptr});
139-
break;
140-
case COPY: {
141-
Register DstReg = MI.getOperand(0).getReg();
142-
Register SrcReg = MI.getOperand(1).getReg();
143-
144-
const RegisterBank *DstRB = getRegBank(DstReg, MRI, TRI);
145-
const RegisterBank *SrcRB = getRegBank(SrcReg, MRI, TRI);
146-
147-
if (!DstRB)
148-
DstRB = SrcRB;
149-
else if (!SrcRB)
150-
SrcRB = DstRB;
151-
152-
assert(DstRB && SrcRB && "Both RegBank were nullptr");
153-
154-
if (DstRB != SrcRB) {
155-
break; // for now, only allow no-op copies
62+
// Track the size and bank of each register. We don't do partial mappings.
63+
SmallVector<unsigned, 8> OpSize(NumOperands);
64+
SmallVector<WebAssembly::PartialMappingIdx, 8> OpRegBankIdx(NumOperands);
65+
for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
66+
auto &MO = MI.getOperand(Idx);
67+
if (!MO.isReg() || !MO.getReg())
68+
continue;
69+
70+
LLT Ty = MRI.getType(MO.getReg());
71+
if (!Ty.isValid())
72+
continue;
73+
74+
OpSize[Idx] = Ty.getSizeInBits().getKnownMinValue();
75+
76+
if (Ty.isInteger()) {
77+
if (OpSize[Idx] == 32) {
78+
OpRegBankIdx[Idx] = WebAssembly::PMI_I32;
79+
} else if (OpSize[Idx] == 64) {
80+
OpRegBankIdx[Idx] = WebAssembly::PMI_I64;
81+
}
15682
}
157-
158-
return getInstructionMapping(
159-
MappingID, /*Cost=*/1, &Op0IntValueMapping,
160-
// We only care about the mapping of the destination for COPY.
161-
1);
162-
}
16383
}
16484

165-
if (!OperandsMapping)
166-
return getInvalidInstructionMapping();
85+
SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands);
86+
for (unsigned Idx = 0; Idx < NumOperands; ++Idx) {
87+
if (MI.getOperand(Idx).isReg() && MI.getOperand(Idx).getReg()) {
88+
LLT Ty = MRI.getType(MI.getOperand(Idx).getReg());
89+
if (!Ty.isValid())
90+
continue;
91+
92+
if (OpRegBankIdx[Idx] <= 0) {
93+
return getInvalidInstructionMapping();
94+
}
95+
96+
const auto &Mapping = getValueMapping(
97+
&WebAssembly::PartMappings[OpRegBankIdx[Idx] - WebAssembly::PMI_Min],
98+
1);
99+
100+
if (!Mapping.isValid())
101+
return getInvalidInstructionMapping();
102+
103+
OpdsMapping[Idx] = &Mapping;
104+
}
105+
}
167106

168-
return getInstructionMapping(MappingID, /*Cost=*/1, OperandsMapping,
169-
NumOperands);
107+
return getInstructionMapping(MappingID, /*Cost=*/1,
108+
getOperandsMapping(OpdsMapping), NumOperands);
170109
}

llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
215215

216216
basicCheckForEHAndSjLj(this);
217217
initAsmInfo();
218+
219+
LLT::setUseExtended(true);
220+
218221
// Note that we don't use setRequiresStructuredCFG(true). It disables
219222
// optimizations than we're ok with, and want, such as critical edge
220223
// splitting and tail merging.

llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/anyext.mir

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ body: |
1313
; CHECK-NEXT: {{ $}}
1414
; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
1515
; CHECK-NEXT: RETURN [[ARGUMENT_i32_]], implicit-def $arguments
16-
%1:i32(s32) = ARGUMENT_i32 0, implicit $arguments
17-
%0:_(s8) = G_TRUNC %1(s32)
18-
%2:i32(s32) = G_ANYEXT %0(s8)
19-
RETURN %2(s32), implicit-def $arguments
16+
%1:i32(i32) = ARGUMENT_i32 0, implicit $arguments
17+
%0:_(i8) = G_TRUNC %1(i32)
18+
%2:i32(i32) = G_ANYEXT %0(i8)
19+
RETURN %2(i32), implicit-def $arguments
2020
...
2121
---
2222
name: aext_i8_i64
@@ -31,10 +31,10 @@ body: |
3131
; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
3232
; CHECK-NEXT: [[I64_EXTEND_U_I32_:%[0-9]+]]:i64 = I64_EXTEND_U_I32 [[ARGUMENT_i32_]], implicit-def dead $arguments
3333
; CHECK-NEXT: RETURN [[I64_EXTEND_U_I32_]], implicit-def $arguments
34-
%1:i32(s32) = ARGUMENT_i32 0, implicit $arguments
35-
%0:_(s8) = G_TRUNC %1(s32)
36-
%2:i64(s64) = G_ANYEXT %0(s8)
37-
RETURN %2(s64), implicit-def $arguments
34+
%1:i32(i32) = ARGUMENT_i32 0, implicit $arguments
35+
%0:_(i8) = G_TRUNC %1(i32)
36+
%2:i64(i64) = G_ANYEXT %0(i8)
37+
RETURN %2(i64), implicit-def $arguments
3838
...
3939

4040
---
@@ -49,10 +49,10 @@ body: |
4949
; CHECK-NEXT: {{ $}}
5050
; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
5151
; CHECK-NEXT: RETURN [[ARGUMENT_i32_]], implicit-def $arguments
52-
%1:i32(s32) = ARGUMENT_i32 0, implicit $arguments
53-
%0:_(s16) = G_TRUNC %1(s32)
54-
%2:i32(s32) = G_ANYEXT %0(s16)
55-
RETURN %2(s32), implicit-def $arguments
52+
%1:i32(i32) = ARGUMENT_i32 0, implicit $arguments
53+
%0:_(i16) = G_TRUNC %1(i32)
54+
%2:i32(i32) = G_ANYEXT %0(i16)
55+
RETURN %2(i32), implicit-def $arguments
5656
...
5757
---
5858
name: aext_i16_i64
@@ -67,10 +67,10 @@ body: |
6767
; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
6868
; CHECK-NEXT: [[I64_EXTEND_U_I32_:%[0-9]+]]:i64 = I64_EXTEND_U_I32 [[ARGUMENT_i32_]], implicit-def dead $arguments
6969
; CHECK-NEXT: RETURN [[I64_EXTEND_U_I32_]], implicit-def $arguments
70-
%1:i32(s32) = ARGUMENT_i32 0, implicit $arguments
71-
%0:_(s16) = G_TRUNC %1(s32)
72-
%2:i64(s64) = G_ANYEXT %0(s16)
73-
RETURN %2(s64), implicit-def $arguments
70+
%1:i32(i32) = ARGUMENT_i32 0, implicit $arguments
71+
%0:_(i16) = G_TRUNC %1(i32)
72+
%2:i64(i64) = G_ANYEXT %0(i16)
73+
RETURN %2(i64), implicit-def $arguments
7474
...
7575
---
7676
name: aext_i32_i64
@@ -85,7 +85,7 @@ body: |
8585
; CHECK-NEXT: [[ARGUMENT_i32_:%[0-9]+]]:i32 = ARGUMENT_i32 0, implicit $arguments
8686
; CHECK-NEXT: [[I64_EXTEND_U_I32_:%[0-9]+]]:i64 = I64_EXTEND_U_I32 [[ARGUMENT_i32_]], implicit-def dead $arguments
8787
; CHECK-NEXT: RETURN [[I64_EXTEND_U_I32_]], implicit-def $arguments
88-
%0:i32(s32) = ARGUMENT_i32 0, implicit $arguments
89-
%1:i64(s64) = G_ANYEXT %0(s32)
90-
RETURN %1(s64), implicit-def $arguments
88+
%0:i32(i32) = ARGUMENT_i32 0, implicit $arguments
89+
%1:i64(i64) = G_ANYEXT %0(i32)
90+
RETURN %1(i64), implicit-def $arguments
9191
...

llvm/test/CodeGen/WebAssembly/GlobalISel/instructions/ashr.mir

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ body: |
1515
; CHECK-NEXT: [[CONST_I32_:%[0-9]+]]:i32 = CONST_I32 21, implicit-def dead $arguments
1616
; CHECK-NEXT: [[SHR_S_I32_:%[0-9]+]]:i32 = SHR_S_I32 [[ARGUMENT_i32_]], [[CONST_I32_]], implicit-def dead $arguments
1717
; CHECK-NEXT: RETURN [[SHR_S_I32_]], implicit-def $arguments
18-
%0:i32(s32) = ARGUMENT_i32 0, implicit $arguments
19-
%1:_(s8) = G_CONSTANT i8 21
20-
%2:_(s32) = G_ASHR %0, %1
21-
RETURN %2(s32), implicit-def $arguments
18+
%0:i32(i32) = ARGUMENT_i32 0, implicit $arguments
19+
%1:_(i8) = G_CONSTANT i8 21
20+
%2:_(i32) = G_ASHR %0, %1
21+
RETURN %2(i32), implicit-def $arguments
2222
...
2323
---
2424
name: ashrv_i32_i8
@@ -36,11 +36,11 @@ body: |
3636
; CHECK-NEXT: [[AND_I32_:%[0-9]+]]:i32 = AND_I32 [[ARGUMENT_i32_1]], [[CONST_I32_]], implicit-def dead $arguments
3737
; CHECK-NEXT: [[SHR_S_I32_:%[0-9]+]]:i32 = SHR_S_I32 [[ARGUMENT_i32_]], [[AND_I32_]], implicit-def dead $arguments
3838
; CHECK-NEXT: RETURN [[SHR_S_I32_]], implicit-def $arguments
39-
%0:i32(s32) = ARGUMENT_i32 0, implicit $arguments
40-
%2:i32(s32) = ARGUMENT_i32 1, implicit $arguments
41-
%1:_(s8) = G_TRUNC %2(s32)
42-
%3:_(s32) = G_ASHR %0, %1
43-
RETURN %3(s32), implicit-def $arguments
39+
%0:i32(i32) = ARGUMENT_i32 0, implicit $arguments
40+
%2:i32(i32) = ARGUMENT_i32 1, implicit $arguments
41+
%1:_(i8) = G_TRUNC %2(i32)
42+
%3:_(i32) = G_ASHR %0, %1
43+
RETURN %3(i32), implicit-def $arguments
4444
...
4545

4646
---
@@ -59,10 +59,10 @@ body: |
5959
; CHECK-NEXT: [[AND_I64_:%[0-9]+]]:i64 = AND_I64 [[CONST_I64_]], [[CONST_I64_1]], implicit-def dead $arguments
6060
; CHECK-NEXT: [[SHR_S_I64_:%[0-9]+]]:i64 = SHR_S_I64 [[ARGUMENT_i64_]], [[AND_I64_]], implicit-def dead $arguments
6161
; CHECK-NEXT: RETURN [[SHR_S_I64_]], implicit-def $arguments
62-
%0:i64(s64) = ARGUMENT_i64 0, implicit $arguments
63-
%1:_(s8) = G_CONSTANT i8 37
64-
%2:_(s64) = G_ASHR %0, %1
65-
RETURN %2(s64), implicit-def $arguments
62+
%0:i64(i64) = ARGUMENT_i64 0, implicit $arguments
63+
%1:_(i8) = G_CONSTANT i8 37
64+
%2:_(i64) = G_ASHR %0, %1
65+
RETURN %2(i64), implicit-def $arguments
6666
...
6767
---
6868
name: ashrv_i64_i8
@@ -81,9 +81,9 @@ body: |
8181
; CHECK-NEXT: [[AND_I64_:%[0-9]+]]:i64 = AND_I64 [[I64_EXTEND_U_I32_]], [[CONST_I64_]], implicit-def dead $arguments
8282
; CHECK-NEXT: [[SHR_S_I64_:%[0-9]+]]:i64 = SHR_S_I64 [[ARGUMENT_i64_]], [[AND_I64_]], implicit-def dead $arguments
8383
; CHECK-NEXT: RETURN [[SHR_S_I64_]], implicit-def $arguments
84-
%0:i64(s64) = ARGUMENT_i64 0, implicit $arguments
85-
%2:i32(s32) = ARGUMENT_i32 1, implicit $arguments
86-
%1:_(s8) = G_TRUNC %2(s32)
87-
%3:_(s64) = G_ASHR %0, %1
88-
RETURN %3(s64), implicit-def $arguments
84+
%0:i64(i64) = ARGUMENT_i64 0, implicit $arguments
85+
%2:i32(i32) = ARGUMENT_i32 1, implicit $arguments
86+
%1:_(i8) = G_TRUNC %2(i32)
87+
%3:_(i64) = G_ASHR %0, %1
88+
RETURN %3(i64), implicit-def $arguments
8989
...

0 commit comments

Comments
 (0)