Skip to content

Commit 4c7f820

Browse files
committed
Update @llvm.powi to handle different int sizes for the exponent
This can be seen as a follow up to commit 0ee439b, that changed the second argument of __powidf2, __powisf2 and __powitf2 in compiler-rt from si_int to int. That was to align with how those runtimes are defined in libgcc. One thing that seem to have been missing in that patch was to make sure that the rest of LLVM also handle that the argument now depends on the size of int (not using the si_int machine mode for 32-bit). When using __builtin_powi for a target with 16-bit int clang crashed. And when emitting libcalls to those rtlib functions, typically when lowering @llvm.powi), the backend would always prepare the exponent argument as an i32 which caused miscompiles when the rtlib was compiled with 16-bit int. The solution used here is to use an overloaded type for the second argument in @llvm.powi. This way clang can use the "correct" type when lowering __builtin_powi, and then later when emitting the libcall it is assumed that the type used in @llvm.powi matches the rtlib function. One thing that needed some extra attention was that when vectorizing calls several passes did not support that several arguments could be overloaded in the intrinsics. This patch allows overload of a scalar operand by adding hasVectorInstrinsicOverloadedScalarOpd, with an entry for powi. Differential Revision: https://reviews.llvm.org/D99439
1 parent 204014e commit 4c7f820

File tree

74 files changed

+505
-326
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+505
-326
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2946,10 +2946,21 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
29462946

29472947
case Builtin::BI__builtin_powi:
29482948
case Builtin::BI__builtin_powif:
2949-
case Builtin::BI__builtin_powil:
2950-
return RValue::get(emitBinaryMaybeConstrainedFPBuiltin(
2951-
*this, E, Intrinsic::powi, Intrinsic::experimental_constrained_powi));
2949+
case Builtin::BI__builtin_powil: {
2950+
llvm::Value *Src0 = EmitScalarExpr(E->getArg(0));
2951+
llvm::Value *Src1 = EmitScalarExpr(E->getArg(1));
29522952

2953+
if (Builder.getIsFPConstrained()) {
2954+
CodeGenFunction::CGFPOptionsRAII FPOptsRAII(*this, E);
2955+
Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_powi,
2956+
Src0->getType());
2957+
return RValue::get(Builder.CreateConstrainedFPCall(F, { Src0, Src1 }));
2958+
}
2959+
2960+
Function *F = CGM.getIntrinsic(Intrinsic::powi,
2961+
{ Src0->getType(), Src1->getType() });
2962+
return RValue::get(Builder.CreateCall(F, { Src0, Src1 }));
2963+
}
29532964
case Builtin::BI__builtin_isgreater:
29542965
case Builtin::BI__builtin_isgreaterequal:
29552966
case Builtin::BI__builtin_isless:

clang/test/CodeGen/avr-builtins.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,24 @@ unsigned long long byteswap64(unsigned long long x) {
104104

105105
// CHECK: define{{.*}} i64 @byteswap64
106106
// CHECK: i64 @llvm.bswap.i64(i64
107+
108+
double powi(double x, int y) {
109+
return __builtin_powi(x, y);
110+
}
111+
112+
// CHECK: define{{.*}} float @powi
113+
// CHECK: float @llvm.powi.f32.i16(float %0, i16 %1)
114+
115+
float powif(float x, int y) {
116+
return __builtin_powif(x, y);
117+
}
118+
119+
// CHECK: define{{.*}} float @powif
120+
// CHECK: float @llvm.powi.f32.i16(float %0, i16 %1)
121+
122+
long double powil(long double x, int y) {
123+
return __builtin_powil(x, y);
124+
}
125+
126+
// CHECK: define{{.*}} float @powil
127+
// CHECK: float @llvm.powi.f32.i16(float %0, i16 %1)

clang/test/CodeGen/math-builtins.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,12 +133,12 @@ void foo(double *d, float f, float *fp, long double *l, int *i, const char *c) {
133133

134134
__builtin_powi(f,f); __builtin_powif(f,f); __builtin_powil(f,f);
135135

136-
// NO__ERRNO: declare double @llvm.powi.f64(double, i32) [[READNONE_INTRINSIC]]
137-
// NO__ERRNO: declare float @llvm.powi.f32(float, i32) [[READNONE_INTRINSIC]]
138-
// NO__ERRNO: declare x86_fp80 @llvm.powi.f80(x86_fp80, i32) [[READNONE_INTRINSIC]]
139-
// HAS_ERRNO: declare double @llvm.powi.f64(double, i32) [[READNONE_INTRINSIC]]
140-
// HAS_ERRNO: declare float @llvm.powi.f32(float, i32) [[READNONE_INTRINSIC]]
141-
// HAS_ERRNO: declare x86_fp80 @llvm.powi.f80(x86_fp80, i32) [[READNONE_INTRINSIC]]
136+
// NO__ERRNO: declare double @llvm.powi.f64.i32(double, i32) [[READNONE_INTRINSIC]]
137+
// NO__ERRNO: declare float @llvm.powi.f32.i32(float, i32) [[READNONE_INTRINSIC]]
138+
// NO__ERRNO: declare x86_fp80 @llvm.powi.f80.i32(x86_fp80, i32) [[READNONE_INTRINSIC]]
139+
// HAS_ERRNO: declare double @llvm.powi.f64.i32(double, i32) [[READNONE_INTRINSIC]]
140+
// HAS_ERRNO: declare float @llvm.powi.f32.i32(float, i32) [[READNONE_INTRINSIC]]
141+
// HAS_ERRNO: declare x86_fp80 @llvm.powi.f80.i32(x86_fp80, i32) [[READNONE_INTRINSIC]]
142142

143143
/* math */
144144
__builtin_acos(f); __builtin_acosf(f); __builtin_acosl(f); __builtin_acosf128(f);

clang/test/CodeGen/msp430-builtins.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2+
// RUN: %clang_cc1 -triple msp430-unknown-unknown -O3 -emit-llvm -o- %s | FileCheck %s
3+
// REQUIRES: msp430-registered-target
4+
5+
_Static_assert(sizeof(int) == 2, "Assumption failed");
6+
_Static_assert(sizeof(long) == 4, "Assumption failed");
7+
_Static_assert(sizeof(long long) == 8, "Assumption failed");
8+
_Static_assert(sizeof(float) == 4, "Assumption failed");
9+
_Static_assert(sizeof(double) == 8, "Assumption failed");
10+
_Static_assert(sizeof(long double) == 8, "Assumption failed");
11+
12+
// CHECK-LABEL: @powif(
13+
// CHECK-NEXT: entry:
14+
// CHECK-NEXT: [[TMP0:%.*]] = tail call float @llvm.powi.f32.i16(float [[X:%.*]], i16 [[Y:%.*]])
15+
// CHECK-NEXT: ret float [[TMP0]]
16+
//
17+
float powif(float x, int y) {
18+
return __builtin_powif(x, y);
19+
}
20+
21+
// CHECK-LABEL: @powi(
22+
// CHECK-NEXT: entry:
23+
// CHECK-NEXT: [[TMP0:%.*]] = tail call double @llvm.powi.f64.i16(double [[X:%.*]], i16 [[Y:%.*]])
24+
// CHECK-NEXT: ret double [[TMP0]]
25+
//
26+
double powi(double x, int y) {
27+
return __builtin_powi(x, y);
28+
}
29+
30+
// CHECK-LABEL: @powil(
31+
// CHECK-NEXT: entry:
32+
// CHECK-NEXT: [[TMP0:%.*]] = tail call double @llvm.powi.f64.i16(double [[X:%.*]], i16 [[Y:%.*]])
33+
// CHECK-NEXT: ret double [[TMP0]]
34+
//
35+
long double powil(long double x, int y) {
36+
return __builtin_powil(x, y);
37+
}

llvm/docs/LangRef.rst

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13647,13 +13647,16 @@ This is an overloaded intrinsic. You can use ``llvm.powi`` on any
1364713647
floating-point or vector of floating-point type. Not all targets support
1364813648
all types however.
1364913649

13650+
Generally, the only supported type for the exponent is the one matching
13651+
with the C type ``int``.
13652+
1365013653
::
1365113654

13652-
declare float @llvm.powi.f32(float %Val, i32 %power)
13653-
declare double @llvm.powi.f64(double %Val, i32 %power)
13654-
declare x86_fp80 @llvm.powi.f80(x86_fp80 %Val, i32 %power)
13655-
declare fp128 @llvm.powi.f128(fp128 %Val, i32 %power)
13656-
declare ppc_fp128 @llvm.powi.ppcf128(ppc_fp128 %Val, i32 %power)
13655+
declare float @llvm.powi.f32.i32(float %Val, i32 %power)
13656+
declare double @llvm.powi.f64.i16(double %Val, i16 %power)
13657+
declare x86_fp80 @llvm.powi.f80.i32(x86_fp80 %Val, i32 %power)
13658+
declare fp128 @llvm.powi.f128.i32(fp128 %Val, i32 %power)
13659+
declare ppc_fp128 @llvm.powi.ppcf128.i32(ppc_fp128 %Val, i32 %power)
1365713660

1365813661
Overview:
1365913662
"""""""""

llvm/include/llvm/Analysis/VectorUtils.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,11 @@ bool isTriviallyVectorizable(Intrinsic::ID ID);
317317
/// Identifies if the vector form of the intrinsic has a scalar operand.
318318
bool hasVectorInstrinsicScalarOpd(Intrinsic::ID ID, unsigned ScalarOpdIdx);
319319

320+
/// Identifies if the vector form of the intrinsic has a scalar operand that has
321+
/// an overloaded type.
322+
bool hasVectorInstrinsicOverloadedScalarOpd(Intrinsic::ID ID,
323+
unsigned ScalarOpdIdx);
324+
320325
/// Returns intrinsic ID for call.
321326
/// For the input call instruction it finds mapping intrinsic and returns
322327
/// its intrinsic ID, in case it does not found it return not_intrinsic.

llvm/include/llvm/CodeGen/ISDOpcodes.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -851,8 +851,8 @@ enum NodeType {
851851
STRICT_FP_TO_FP16,
852852

853853
/// Perform various unary floating-point operations inspired by libm. For
854-
/// FPOWI, the result is undefined if if the integer operand doesn't fit
855-
/// into 32 bits.
854+
/// FPOWI, the result is undefined if if the integer operand doesn't fit into
855+
/// sizeof(int).
856856
FNEG,
857857
FABS,
858858
FSQRT,

llvm/include/llvm/IR/Intrinsics.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,7 @@ let IntrProperties = [IntrNoMem, IntrSpeculatable, IntrWillReturn] in {
652652
// rounding mode. LLVM purposely does not model changes to the FP
653653
// environment so they can be treated as readnone.
654654
def int_sqrt : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
655-
def int_powi : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, llvm_i32_ty]>;
655+
def int_powi : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>, llvm_anyint_ty]>;
656656
def int_sin : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
657657
def int_cos : DefaultAttrsIntrinsic<[llvm_anyfloat_ty], [LLVMMatchType<0>]>;
658658
def int_pow : DefaultAttrsIntrinsic<[llvm_anyfloat_ty],

llvm/lib/Analysis/VectorUtils.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,16 @@ bool llvm::hasVectorInstrinsicScalarOpd(Intrinsic::ID ID,
114114
}
115115
}
116116

117+
bool llvm::hasVectorInstrinsicOverloadedScalarOpd(Intrinsic::ID ID,
118+
unsigned ScalarOpdIdx) {
119+
switch (ID) {
120+
case Intrinsic::powi:
121+
return (ScalarOpdIdx == 1);
122+
default:
123+
return false;
124+
}
125+
}
126+
117127
/// Returns intrinsic ID for call.
118128
/// For the input call instruction it finds mapping intrinsic and returns
119129
/// its ID, in case it does not found it return not_intrinsic.

llvm/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4044,6 +4044,17 @@ void SelectionDAGLegalize::ConvertNodeToLibcall(SDNode *Node) {
40444044
Exponent));
40454045
break;
40464046
}
4047+
unsigned Offset = Node->isStrictFPOpcode() ? 1 : 0;
4048+
bool ExponentHasSizeOfInt =
4049+
DAG.getLibInfo().getIntSize() ==
4050+
Node->getOperand(1 + Offset).getValueType().getSizeInBits();
4051+
if (!ExponentHasSizeOfInt) {
4052+
// If the exponent does not match with sizeof(int) a libcall to
4053+
// RTLIB::POWI would use the wrong type for the argument.
4054+
DAG.getContext()->emitError("POWI exponent does not match sizeof(int)");
4055+
Results.push_back(DAG.getUNDEF(Node->getValueType(0)));
4056+
break;
4057+
}
40474058
ExpandFPLibCall(Node, LC, Results);
40484059
break;
40494060
}

0 commit comments

Comments
 (0)