Skip to content

Commit 2fe3694

Browse files
[EVM][DAGCombine] Expand SELECT of constant to arithmetic
This patch implements following optimization: | Source pattern | Rewritten form | Proof (IR equivalent) | |--------------------------|--------------------|-------------------------------------| | select C, X, C2 | C2 + (X - C2) * C | https://alive2.llvm.org/ce/z/V2Cd9h | | select C, C1, Y | Y + (C1 - Y) * C | https://alive2.llvm.org/ce/z/g3ki-b | | select C, C1, C2 C1 > C2 | C2 + (C1 - C2) * C | https://alive2.llvm.org/ce/z/cOCHY_ | | select C, C1, C2 C1 < C2 | C2 - (C2 - C1) * C | https://alive2.llvm.org/ce/z/P8jkjd | When we have select of two constants, we are doing two different transformations to avoid generating negative constants, which are expensive in EVM. Signed-off-by: Vladimir Radosavljevic <[email protected]>
1 parent 499b76d commit 2fe3694

File tree

2 files changed

+93
-93
lines changed

2 files changed

+93
-93
lines changed

llvm/lib/Target/EVM/EVMISelLowering.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,49 @@ SDValue EVMTargetLowering::combineSELECT(SDNode *N,
876876
return DAG.getNode(ISD::OR, DL, VT, Neg, DAG.getFreeze(FalseV));
877877
}
878878

879+
// fold (Cond ? C1 : C2) -> (C2 + (C1 - C2) * Cond) if (C1 > C2)
880+
// fold (Cond ? C1 : C2) -> (C2 - (C2 - C1) * Cond) if (C1 < C2)
881+
//
882+
// We distinguish between C1 > C2 and C1 < C2 to avoid generating
883+
// negative constants, which are expensive in EVM.
884+
if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV)) {
885+
APInt C1Val = cast<ConstantSDNode>(TrueV)->getAPIntValue();
886+
APInt C2Val = cast<ConstantSDNode>(FalseV)->getAPIntValue();
887+
888+
// This should never happen, but just in case.
889+
if (C1Val == C2Val)
890+
return TrueV;
891+
892+
unsigned Opc = 0;
893+
SDValue Scale;
894+
if (C1Val.sgt(C2Val)) {
895+
Opc = ISD::ADD;
896+
Scale = DAG.getConstant(C1Val - C2Val, DL, VT);
897+
} else {
898+
// Use sub to avoid generating negative constants.
899+
Opc = ISD::SUB;
900+
Scale = DAG.getConstant(C2Val - C1Val, DL, VT);
901+
}
902+
903+
SDValue Mul = DAG.getNode(ISD::MUL, DL, VT, CondV, Scale);
904+
return DAG.getNode(Opc, DL, VT, FalseV, Mul);
905+
}
906+
907+
// fold (Cond ? X : C) -> (C + (X* - C) * Cond)
908+
// fold (Cond ? C : Y) -> (Y* + (C - Y*) * Cond)
909+
if (isa<ConstantSDNode>(TrueV) || isa<ConstantSDNode>(FalseV)) {
910+
if (!isa<ConstantSDNode>(TrueV))
911+
TrueV = freeze(TrueV);
912+
else if (!isa<ConstantSDNode>(FalseV))
913+
FalseV = freeze(FalseV);
914+
else
915+
llvm_unreachable("Unexpected select operands");
916+
917+
SDValue Sub = DAG.getNode(ISD::SUB, DL, VT, TrueV, FalseV);
918+
SDValue Mul = DAG.getNode(ISD::MUL, DL, VT, CondV, Sub);
919+
return DAG.getNode(ISD::ADD, DL, VT, FalseV, Mul);
920+
}
921+
879922
if (SDValue V = tryFoldSelectIntoOp(N, DAG, TrueV, FalseV, /*Swapped=*/false))
880923
return V;
881924
// NOLINTNEXTLINE(readability-suspicious-call-argument)

llvm/test/CodeGen/EVM/select-const.ll

Lines changed: 50 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -48,20 +48,13 @@ define i256 @select_const_int_harder(i1 %a) {
4848
; CHECK-LABEL: select_const_int_harder:
4949
; CHECK: ; %bb.0:
5050
; CHECK-NEXT: JUMPDEST
51+
; CHECK-NEXT: PUSH1 0x26
52+
; CHECK-NEXT: SWAP1
5153
; CHECK-NEXT: PUSH1 0x1
5254
; CHECK-NEXT: AND
53-
; CHECK-NEXT: ISZERO
54-
; CHECK-NEXT: PUSH4 @.BB3_2
55-
; CHECK-NEXT: JUMPI
56-
; CHECK-NEXT: ; %bb.1:
57-
; CHECK-NEXT: PUSH1 0x6
58-
; CHECK-NEXT: PUSH4 @.BB3_3
59-
; CHECK-NEXT: JUMP
60-
; CHECK-NEXT: .BB3_2:
61-
; CHECK-NEXT: JUMPDEST
62-
; CHECK-NEXT: PUSH1 0x26
63-
; CHECK-NEXT: .BB3_3:
64-
; CHECK-NEXT: JUMPDEST
55+
; CHECK-NEXT: PUSH1 0x5
56+
; CHECK-NEXT: SHL
57+
; CHECK-NEXT: XOR
6558
; CHECK-NEXT: SWAP1
6659
; CHECK-NEXT: JUMP
6760
%1 = select i1 %a, i256 6, i256 38
@@ -306,20 +299,13 @@ define i256 @select_196_184(i1 %a) {
306299
; CHECK-LABEL: select_196_184:
307300
; CHECK: ; %bb.0:
308301
; CHECK-NEXT: JUMPDEST
302+
; CHECK-NEXT: PUSH1 0xC
303+
; CHECK-NEXT: PUSH1 0xB8
304+
; CHECK-NEXT: SWAP2
309305
; CHECK-NEXT: PUSH1 0x1
310306
; CHECK-NEXT: AND
311-
; CHECK-NEXT: ISZERO
312-
; CHECK-NEXT: PUSH4 @.BB20_2
313-
; CHECK-NEXT: JUMPI
314-
; CHECK-NEXT: ; %bb.1:
315-
; CHECK-NEXT: PUSH1 0xC4
316-
; CHECK-NEXT: PUSH4 @.BB20_3
317-
; CHECK-NEXT: JUMP
318-
; CHECK-NEXT: .BB20_2:
319-
; CHECK-NEXT: JUMPDEST
320-
; CHECK-NEXT: PUSH1 0xB8
321-
; CHECK-NEXT: .BB20_3:
322-
; CHECK-NEXT: JUMPDEST
307+
; CHECK-NEXT: MUL
308+
; CHECK-NEXT: ADD
323309
; CHECK-NEXT: SWAP1
324310
; CHECK-NEXT: JUMP
325311
%1 = select i1 %a, i256 196, i256 184
@@ -330,20 +316,13 @@ define i256 @select_184_196(i1 %a) {
330316
; CHECK-LABEL: select_184_196:
331317
; CHECK: ; %bb.0:
332318
; CHECK-NEXT: JUMPDEST
319+
; CHECK-NEXT: PUSH1 0xC
320+
; CHECK-NEXT: SWAP1
333321
; CHECK-NEXT: PUSH1 0x1
334322
; CHECK-NEXT: AND
335-
; CHECK-NEXT: ISZERO
336-
; CHECK-NEXT: PUSH4 @.BB21_2
337-
; CHECK-NEXT: JUMPI
338-
; CHECK-NEXT: ; %bb.1:
339-
; CHECK-NEXT: PUSH1 0xB8
340-
; CHECK-NEXT: PUSH4 @.BB21_3
341-
; CHECK-NEXT: JUMP
342-
; CHECK-NEXT: .BB21_2:
343-
; CHECK-NEXT: JUMPDEST
323+
; CHECK-NEXT: MUL
344324
; CHECK-NEXT: PUSH1 0xC4
345-
; CHECK-NEXT: .BB21_3:
346-
; CHECK-NEXT: JUMPDEST
325+
; CHECK-NEXT: SUB
347326
; CHECK-NEXT: SWAP1
348327
; CHECK-NEXT: JUMP
349328
%1 = select i1 %a, i256 184, i256 196
@@ -354,22 +333,14 @@ define i256 @select_n196_n184(i1 %a) {
354333
; CHECK-LABEL: select_n196_n184:
355334
; CHECK: ; %bb.0:
356335
; CHECK-NEXT: JUMPDEST
336+
; CHECK-NEXT: PUSH1 0xC
337+
; CHECK-NEXT: SWAP1
357338
; CHECK-NEXT: PUSH1 0x1
358339
; CHECK-NEXT: AND
359-
; CHECK-NEXT: ISZERO
360-
; CHECK-NEXT: PUSH4 @.BB22_2
361-
; CHECK-NEXT: JUMPI
362-
; CHECK-NEXT: ; %bb.1:
363-
; CHECK-NEXT: PUSH1 0xC3
364-
; CHECK-NEXT: NOT
365-
; CHECK-NEXT: PUSH4 @.BB22_3
366-
; CHECK-NEXT: JUMP
367-
; CHECK-NEXT: .BB22_2:
368-
; CHECK-NEXT: JUMPDEST
340+
; CHECK-NEXT: MUL
369341
; CHECK-NEXT: PUSH1 0xB7
370342
; CHECK-NEXT: NOT
371-
; CHECK-NEXT: .BB22_3:
372-
; CHECK-NEXT: JUMPDEST
343+
; CHECK-NEXT: SUB
373344
; CHECK-NEXT: SWAP1
374345
; CHECK-NEXT: JUMP
375346
%1 = select i1 %a, i256 -196, i256 -184
@@ -380,22 +351,13 @@ define i256 @select_n184_n196(i1 %a) {
380351
; CHECK-LABEL: select_n184_n196:
381352
; CHECK: ; %bb.0:
382353
; CHECK-NEXT: JUMPDEST
354+
; CHECK-NEXT: PUSH1 0xC
355+
; CHECK-NEXT: PUSH1 0xC4
356+
; CHECK-NEXT: SWAP2
383357
; CHECK-NEXT: PUSH1 0x1
384358
; CHECK-NEXT: AND
385-
; CHECK-NEXT: ISZERO
386-
; CHECK-NEXT: PUSH4 @.BB23_2
387-
; CHECK-NEXT: JUMPI
388-
; CHECK-NEXT: ; %bb.1:
389-
; CHECK-NEXT: PUSH1 0xB7
390-
; CHECK-NEXT: NOT
391-
; CHECK-NEXT: PUSH4 @.BB23_3
392-
; CHECK-NEXT: JUMP
393-
; CHECK-NEXT: .BB23_2:
394-
; CHECK-NEXT: JUMPDEST
395-
; CHECK-NEXT: PUSH1 0xC3
396-
; CHECK-NEXT: NOT
397-
; CHECK-NEXT: .BB23_3:
398-
; CHECK-NEXT: JUMPDEST
359+
; CHECK-NEXT: MUL
360+
; CHECK-NEXT: SUB
399361
; CHECK-NEXT: SWAP1
400362
; CHECK-NEXT: JUMP
401363
%1 = select i1 %a, i256 -184, i256 -196
@@ -406,15 +368,15 @@ define i256 @select_var_12345(i1 %a, i256 %b) {
406368
; CHECK-LABEL: select_var_12345:
407369
; CHECK: ; %bb.0:
408370
; CHECK-NEXT: JUMPDEST
371+
; CHECK-NEXT: PUSH2 0x3039
372+
; CHECK-NEXT: DUP1
373+
; CHECK-NEXT: SWAP3
374+
; CHECK-NEXT: SUB
375+
; CHECK-NEXT: SWAP1
409376
; CHECK-NEXT: PUSH1 0x1
410377
; CHECK-NEXT: AND
411-
; CHECK-NEXT: PUSH4 @.BB24_2
412-
; CHECK-NEXT: JUMPI
413-
; CHECK-NEXT: ; %bb.1:
414-
; CHECK-NEXT: POP
415-
; CHECK-NEXT: PUSH2 0x3039
416-
; CHECK-NEXT: .BB24_2:
417-
; CHECK-NEXT: JUMPDEST
378+
; CHECK-NEXT: MUL
379+
; CHECK-NEXT: ADD
418380
; CHECK-NEXT: SWAP1
419381
; CHECK-NEXT: JUMP
420382
%1 = select i1 %a, i256 %b, i256 12345
@@ -425,16 +387,14 @@ define i256 @select_12345_var(i1 %a, i256 %b) {
425387
; CHECK-LABEL: select_12345_var:
426388
; CHECK: ; %bb.0:
427389
; CHECK-NEXT: JUMPDEST
390+
; CHECK-NEXT: DUP2
391+
; CHECK-NEXT: PUSH2 0x3039
392+
; CHECK-NEXT: SUB
393+
; CHECK-NEXT: SWAP1
428394
; CHECK-NEXT: PUSH1 0x1
429395
; CHECK-NEXT: AND
430-
; CHECK-NEXT: ISZERO
431-
; CHECK-NEXT: PUSH4 @.BB25_2
432-
; CHECK-NEXT: JUMPI
433-
; CHECK-NEXT: ; %bb.1:
434-
; CHECK-NEXT: POP
435-
; CHECK-NEXT: PUSH2 0x3039
436-
; CHECK-NEXT: .BB25_2:
437-
; CHECK-NEXT: JUMPDEST
396+
; CHECK-NEXT: MUL
397+
; CHECK-NEXT: ADD
438398
; CHECK-NEXT: SWAP1
439399
; CHECK-NEXT: JUMP
440400
%1 = select i1 %a, i256 12345, i256 %b
@@ -445,16 +405,15 @@ define i256 @select_var_n12345(i1 %a, i256 %b) {
445405
; CHECK-LABEL: select_var_n12345:
446406
; CHECK: ; %bb.0:
447407
; CHECK-NEXT: JUMPDEST
408+
; CHECK-NEXT: PUSH2 0x3039
409+
; CHECK-NEXT: SWAP2
410+
; CHECK-NEXT: DUP3
411+
; CHECK-NEXT: ADD
412+
; CHECK-NEXT: SWAP1
448413
; CHECK-NEXT: PUSH1 0x1
449414
; CHECK-NEXT: AND
450-
; CHECK-NEXT: PUSH4 @.BB26_2
451-
; CHECK-NEXT: JUMPI
452-
; CHECK-NEXT: ; %bb.1:
453-
; CHECK-NEXT: POP
454-
; CHECK-NEXT: PUSH2 0x3038
455-
; CHECK-NEXT: NOT
456-
; CHECK-NEXT: .BB26_2:
457-
; CHECK-NEXT: JUMPDEST
415+
; CHECK-NEXT: MUL
416+
; CHECK-NEXT: SUB
458417
; CHECK-NEXT: SWAP1
459418
; CHECK-NEXT: JUMP
460419
%1 = select i1 %a, i256 %b, i256 -12345
@@ -465,17 +424,15 @@ define i256 @select_n12345_var(i1 %a, i256 %b) {
465424
; CHECK-LABEL: select_n12345_var:
466425
; CHECK: ; %bb.0:
467426
; CHECK-NEXT: JUMPDEST
468-
; CHECK-NEXT: PUSH1 0x1
469-
; CHECK-NEXT: AND
470-
; CHECK-NEXT: ISZERO
471-
; CHECK-NEXT: PUSH4 @.BB27_2
472-
; CHECK-NEXT: JUMPI
473-
; CHECK-NEXT: ; %bb.1:
474-
; CHECK-NEXT: POP
427+
; CHECK-NEXT: DUP2
475428
; CHECK-NEXT: PUSH2 0x3038
476429
; CHECK-NEXT: NOT
477-
; CHECK-NEXT: .BB27_2:
478-
; CHECK-NEXT: JUMPDEST
430+
; CHECK-NEXT: SUB
431+
; CHECK-NEXT: SWAP1
432+
; CHECK-NEXT: PUSH1 0x1
433+
; CHECK-NEXT: AND
434+
; CHECK-NEXT: MUL
435+
; CHECK-NEXT: ADD
479436
; CHECK-NEXT: SWAP1
480437
; CHECK-NEXT: JUMP
481438
%1 = select i1 %a, i256 -12345, i256 %b

0 commit comments

Comments
 (0)