Skip to content

Commit f0c6eb5

Browse files
committed
LLVMCodeBuilder: Implement tan operator
1 parent 2c3c62c commit f0c6eb5

File tree

5 files changed

+92
-0
lines changed

5 files changed

+92
-0
lines changed

src/dev/engine/internal/icodebuilder.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class ICodeBuilder
4545
virtual void createSqrt() = 0;
4646
virtual void createSin() = 0;
4747
virtual void createCos() = 0;
48+
virtual void createTan() = 0;
4849

4950
virtual void beginIfStatement() = 0;
5051
virtual void beginElseBranch() = 0;

src/dev/engine/internal/llvmcodebuilder.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,38 @@ std::shared_ptr<ExecutableCode> LLVMCodeBuilder::finalize()
284284
break;
285285
}
286286

287+
case Step::Type::Tan: {
288+
assert(step.args.size() == 1);
289+
const auto &arg = step.args[0];
290+
// ((mod = rem(x, 360.0)) == -270.0 || mod == 90.0) ? inf : ((mod == -90.0 || mod == 270.0) ? -inf : round(tan(x * pi / 180.0) * 1e10) / 1e10 + 0.0)
291+
// +0.0 to avoid -0.0
292+
llvm::Constant *zero = llvm::ConstantFP::get(m_ctx, llvm::APFloat(0.0));
293+
llvm::Constant *full = llvm::ConstantFP::get(m_ctx, llvm::APFloat(360.0));
294+
llvm::Constant *posInf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), false);
295+
llvm::Constant *negInf = llvm::ConstantFP::getInfinity(m_builder.getDoubleTy(), true);
296+
llvm::Constant *undefined1 = llvm::ConstantFP::get(m_ctx, llvm::APFloat(-270.0));
297+
llvm::Constant *undefined2 = llvm::ConstantFP::get(m_ctx, llvm::APFloat(90.0));
298+
llvm::Constant *undefined3 = llvm::ConstantFP::get(m_ctx, llvm::APFloat(-90.0));
299+
llvm::Constant *undefined4 = llvm::ConstantFP::get(m_ctx, llvm::APFloat(270.0));
300+
llvm::Constant *pi = llvm::ConstantFP::get(m_ctx, llvm::APFloat(std::acos(-1.0)));
301+
llvm::Constant *piDeg = llvm::ConstantFP::get(m_ctx, llvm::APFloat(180.0));
302+
llvm::Constant *factor = llvm::ConstantFP::get(m_ctx, llvm::APFloat(1e10));
303+
llvm::Function *tanFunc = llvm::Intrinsic::getDeclaration(m_module.get(), llvm::Intrinsic::tan, m_builder.getDoubleTy());
304+
llvm::Function *roundFunc = llvm::Intrinsic::getDeclaration(m_module.get(), llvm::Intrinsic::round, m_builder.getDoubleTy());
305+
llvm::Value *num = removeNaN(castValue(arg.second, arg.first));
306+
llvm::Value *mod = m_builder.CreateFRem(num, full);
307+
llvm::Value *isUndefined1 = m_builder.CreateFCmpOEQ(mod, undefined1); // rem(x, 360.0) == -270.0
308+
llvm::Value *isUndefined2 = m_builder.CreateFCmpOEQ(mod, undefined2); // rem(x, 360.0) == 90.0
309+
llvm::Value *isUndefined3 = m_builder.CreateFCmpOEQ(mod, undefined3); // rem(x, 360.0) == -90.0
310+
llvm::Value *isUndefined4 = m_builder.CreateFCmpOEQ(mod, undefined4); // rem(x, 360.0) == 270.0
311+
llvm::Value *tanResult = m_builder.CreateCall(tanFunc, m_builder.CreateFDiv(m_builder.CreateFMul(num, pi), piDeg)); // tan(x * pi / 180)
312+
llvm::Value *rounded = m_builder.CreateCall(roundFunc, m_builder.CreateFMul(tanResult, factor)); // round(tan(x * 180) * 1e10)
313+
llvm::Value *result = m_builder.CreateFAdd(m_builder.CreateFDiv(rounded, factor), zero); // round(tan(x * pi / 180.0) * 1e10) / 1e10 + 0.0
314+
llvm::Value *inner = m_builder.CreateSelect(m_builder.CreateOr(isUndefined3, isUndefined4), negInf, result);
315+
step.functionReturnReg->value = m_builder.CreateSelect(m_builder.CreateOr(isUndefined1, isUndefined2), posInf, inner);
316+
break;
317+
}
318+
287319
case Step::Type::Yield:
288320
if (!m_warp) {
289321
freeHeap();
@@ -692,6 +724,11 @@ void LLVMCodeBuilder::createCos()
692724
createOp(Step::Type::Cos, Compiler::StaticType::Number, Compiler::StaticType::Number, 1);
693725
}
694726

727+
void LLVMCodeBuilder::createTan()
728+
{
729+
createOp(Step::Type::Tan, Compiler::StaticType::Number, Compiler::StaticType::Number, 1);
730+
}
731+
695732
void LLVMCodeBuilder::beginIfStatement()
696733
{
697734
Step step(Step::Type::BeginIf);

src/dev/engine/internal/llvmcodebuilder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class LLVMCodeBuilder : public ICodeBuilder
4747
void createSqrt() override;
4848
void createSin() override;
4949
void createCos() override;
50+
void createTan() override;
5051

5152
void beginIfStatement() override;
5253
void beginElseBranch() override;
@@ -98,6 +99,7 @@ class LLVMCodeBuilder : public ICodeBuilder
9899
Sqrt,
99100
Sin,
100101
Cos,
102+
Tan,
101103
Yield,
102104
BeginIf,
103105
BeginElse,

test/dev/llvm/llvmcodebuilder_test.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1416,6 +1416,57 @@ TEST_F(LLVMCodeBuilderTest, Cos)
14161416
addOpTest(nan, 1.0);
14171417
}
14181418

1419+
TEST_F(LLVMCodeBuilderTest, Tan)
1420+
{
1421+
std::string expected;
1422+
1423+
auto addOpTest = [this, &expected](Value v1, double expectedResult) {
1424+
createBuilder(true);
1425+
1426+
m_builder->addConstValue(v1);
1427+
m_builder->createTan();
1428+
m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number });
1429+
1430+
m_builder->addConstValue(v1);
1431+
m_builder->addFunctionCall("test_const_number", Compiler::StaticType::Number, { Compiler::StaticType::Number });
1432+
m_builder->createTan();
1433+
m_builder->addFunctionCall("test_print_number", Compiler::StaticType::Void, { Compiler::StaticType::Number });
1434+
1435+
std::stringstream stream;
1436+
stream << expectedResult;
1437+
std::string str = stream.str() + '\n';
1438+
std::string expected = str + str;
1439+
1440+
auto code = m_builder->finalize();
1441+
auto ctx = code->createExecutionContext(&m_target);
1442+
1443+
testing::internal::CaptureStdout();
1444+
code->run(ctx.get());
1445+
const std::string quotes1 = v1.isString() ? "\"" : "";
1446+
ASSERT_THAT(testing::internal::GetCapturedStdout(), Eq(expected)) << quotes1 << v1.toString() << quotes1;
1447+
};
1448+
1449+
static const double inf = std::numeric_limits<double>::infinity();
1450+
static const double nan = std::numeric_limits<double>::quiet_NaN();
1451+
1452+
addOpTest(45.0, 1.0);
1453+
addOpTest(90.0, inf);
1454+
addOpTest(270.0, -inf);
1455+
addOpTest(450.0, inf);
1456+
addOpTest(-90.0, -inf);
1457+
addOpTest(-270.0, inf);
1458+
addOpTest(-450.0, -inf);
1459+
addOpTest(180.0, 0.0);
1460+
addOpTest(-180.0, 0.0);
1461+
addOpTest(2.87e-9, 1e-10);
1462+
addOpTest(2.8647e-9, 0.0);
1463+
addOpTest(0.0, 0.0);
1464+
addOpTest(-0.0, 0.0);
1465+
addOpTest(inf, -nan); // negative NaN shouldn't be a problem
1466+
addOpTest(-inf, -nan);
1467+
addOpTest(nan, 0.0);
1468+
}
1469+
14191470
TEST_F(LLVMCodeBuilderTest, Yield)
14201471
{
14211472
auto build = [this]() {

test/mocks/codebuildermock.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class CodeBuilderMock : public ICodeBuilder
3535
MOCK_METHOD(void, createSqrt, (), (override));
3636
MOCK_METHOD(void, createSin, (), (override));
3737
MOCK_METHOD(void, createCos, (), (override));
38+
MOCK_METHOD(void, createTan, (), (override));
3839

3940
MOCK_METHOD(void, beginIfStatement, (), (override));
4041
MOCK_METHOD(void, beginElseBranch, (), (override));

0 commit comments

Comments
 (0)