Skip to content

Commit ad4372c

Browse files
authored
Promote shift RHS to vectors if needed (#4781)
Fixes #3606.
1 parent c32c7ee commit ad4372c

File tree

4 files changed

+25
-177
lines changed

4 files changed

+25
-177
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
- Fix potentially corrupt IR layouts for bit fields. (#4646, #4708)
1515
- Fix potentially corrupt IR layouts for explicitly under-aligned aggregates, a regression introduced in LDC v1.31. (#4734, #4736)
1616
- ELF: Emit (most) instantiated symbols in COMDATs for proper link-time culling. (#3589, #4748)
17+
- Support scalar right-hand-sides when bit-shifting vectors. (#3606, #4781)
1718

1819
# LDC 1.39.0 (2024-07-04)
1920

dmd/expressionsem.d

Lines changed: 19 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -13016,9 +13016,8 @@ version (IN_LLVM)
1301613016
return;
1301713017
}
1301813018

13019-
override void visit(ShlExp exp)
13019+
private void visitShift(BinExp exp)
1302013020
{
13021-
//printf("ShlExp::semantic(), type = %p\n", type);
1302213021
if (exp.type)
1302313022
{
1302413023
result = exp;
@@ -13045,87 +13044,32 @@ version (IN_LLVM)
1304513044
result = exp.incompatibleTypes();
1304613045
return;
1304713046
}
13047+
1304813048
exp.e1 = integralPromotions(exp.e1, sc);
1304913049
if (exp.e2.type.toBasetype().ty != Tvector)
13050-
exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
13050+
{
13051+
Type tb1 = exp.e1.type.toBasetype();
13052+
exp.e2 = exp.e2.castTo(sc, tb1.ty == Tvector ? tb1 : Type.tshiftcnt);
13053+
}
1305113054

1305213055
exp.type = exp.e1.type;
1305313056
result = exp;
1305413057
}
1305513058

13059+
override void visit(ShlExp exp)
13060+
{
13061+
visitShift(exp);
13062+
}
1305613063
override void visit(ShrExp exp)
1305713064
{
13058-
if (exp.type)
13059-
{
13060-
result = exp;
13061-
return;
13062-
}
13063-
13064-
if (Expression ex = binSemanticProp(exp, sc))
13065-
{
13066-
result = ex;
13067-
return;
13068-
}
13069-
Expression e = exp.op_overload(sc);
13070-
if (e)
13071-
{
13072-
result = e;
13073-
return;
13074-
}
13075-
13076-
if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13077-
return setError();
13078-
13079-
if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
13080-
{
13081-
result = exp.incompatibleTypes();
13082-
return;
13083-
}
13084-
exp.e1 = integralPromotions(exp.e1, sc);
13085-
if (exp.e2.type.toBasetype().ty != Tvector)
13086-
exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
13087-
13088-
exp.type = exp.e1.type;
13089-
result = exp;
13065+
visitShift(exp);
1309013066
}
13091-
1309213067
override void visit(UshrExp exp)
1309313068
{
13094-
if (exp.type)
13095-
{
13096-
result = exp;
13097-
return;
13098-
}
13099-
13100-
if (Expression ex = binSemanticProp(exp, sc))
13101-
{
13102-
result = ex;
13103-
return;
13104-
}
13105-
Expression e = exp.op_overload(sc);
13106-
if (e)
13107-
{
13108-
result = e;
13109-
return;
13110-
}
13111-
13112-
if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13113-
return setError();
13114-
13115-
if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
13116-
{
13117-
result = exp.incompatibleTypes();
13118-
return;
13119-
}
13120-
exp.e1 = integralPromotions(exp.e1, sc);
13121-
if (exp.e2.type.toBasetype().ty != Tvector)
13122-
exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
13123-
13124-
exp.type = exp.e1.type;
13125-
result = exp;
13069+
visitShift(exp);
1312613070
}
1312713071

13128-
override void visit(AndExp exp)
13072+
private void visitBinaryBitOp(BinExp exp)
1312913073
{
1313013074
if (exp.type)
1313113075
{
@@ -13180,114 +13124,17 @@ version (IN_LLVM)
1318013124
result = exp;
1318113125
}
1318213126

13127+
override void visit(AndExp exp)
13128+
{
13129+
visitBinaryBitOp(exp);
13130+
}
1318313131
override void visit(OrExp exp)
1318413132
{
13185-
if (exp.type)
13186-
{
13187-
result = exp;
13188-
return;
13189-
}
13190-
13191-
if (Expression ex = binSemanticProp(exp, sc))
13192-
{
13193-
result = ex;
13194-
return;
13195-
}
13196-
Expression e = exp.op_overload(sc);
13197-
if (e)
13198-
{
13199-
result = e;
13200-
return;
13201-
}
13202-
13203-
if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
13204-
{
13205-
exp.type = exp.e1.type;
13206-
result = exp;
13207-
return;
13208-
}
13209-
13210-
if (Expression ex = typeCombine(exp, sc))
13211-
{
13212-
result = ex;
13213-
return;
13214-
}
13215-
13216-
Type tb = exp.type.toBasetype();
13217-
if (tb.ty == Tarray || tb.ty == Tsarray)
13218-
{
13219-
if (!isArrayOpValid(exp))
13220-
{
13221-
result = arrayOpInvalidError(exp);
13222-
return;
13223-
}
13224-
result = exp;
13225-
return;
13226-
}
13227-
if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
13228-
{
13229-
result = exp.incompatibleTypes();
13230-
return;
13231-
}
13232-
if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13233-
return setError();
13234-
13235-
result = exp;
13133+
visitBinaryBitOp(exp);
1323613134
}
13237-
1323813135
override void visit(XorExp exp)
1323913136
{
13240-
if (exp.type)
13241-
{
13242-
result = exp;
13243-
return;
13244-
}
13245-
13246-
if (Expression ex = binSemanticProp(exp, sc))
13247-
{
13248-
result = ex;
13249-
return;
13250-
}
13251-
Expression e = exp.op_overload(sc);
13252-
if (e)
13253-
{
13254-
result = e;
13255-
return;
13256-
}
13257-
13258-
if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
13259-
{
13260-
exp.type = exp.e1.type;
13261-
result = exp;
13262-
return;
13263-
}
13264-
13265-
if (Expression ex = typeCombine(exp, sc))
13266-
{
13267-
result = ex;
13268-
return;
13269-
}
13270-
13271-
Type tb = exp.type.toBasetype();
13272-
if (tb.ty == Tarray || tb.ty == Tsarray)
13273-
{
13274-
if (!isArrayOpValid(exp))
13275-
{
13276-
result = arrayOpInvalidError(exp);
13277-
return;
13278-
}
13279-
result = exp;
13280-
return;
13281-
}
13282-
if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
13283-
{
13284-
result = exp.incompatibleTypes();
13285-
return;
13286-
}
13287-
if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
13288-
return setError();
13289-
13290-
result = exp;
13137+
visitBinaryBitOp(exp);
1329113138
}
1329213139

1329313140
override void visit(LogicalExp exp)

dmd/target.d

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -794,11 +794,6 @@ static if (!IN_LLVM)
794794
if (!IN_LLVM && vecsize != 16 && vecsize != 32)
795795
return false;
796796

797-
// LDC_FIXME:
798-
// Most of the binops only work with `t2` being the same IR type as `tvec`
799-
// (LLVM restriction). We'd need to be more strict here and/or convert
800-
// the rhs to a matching type during codegen (e.g., promote scalars to
801-
// vectors).
802797
bool supported = false;
803798
switch (op)
804799
{

tests/codegen/vector_ops.d

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,11 @@ void main()
4444

4545
const int4 i = [ 1, 2, 3, 4 ];
4646
assert(i << i is [ 2, 8, 24, 64 ]);
47+
assert(i << 2 is [ 4, 8, 12, 16 ]);
48+
assert(i >> int4(1) is [ 0, 1, 1, 2 ]);
49+
assert(i >> 1 is [ 0, 1, 1, 2 ]);
50+
assert(i >>> int4(1) is [ 0, 1, 1, 2 ]);
51+
assert(i >>> 1 is [ 0, 1, 1, 2 ]);
4752

4853
const int4 a = [ 0b1, 0b10, 0b101, 0b100011 ];
4954
const int4 b = 0b110;

0 commit comments

Comments
 (0)