#include "Base/LogicalOpImpl.h"
#include <functional>
#include <map>
#include "Base/CHIRExprWrapper.h"
#include "CGModule.h"
#include "IRBuilder.h"
#include "cangjie/CHIR/IR/Expression/Terminator.h"
#include "cangjie/CHIR/IR/Value/Value.h"
namespace Cangjie {
namespace CodeGen {
llvm::Value* GenerateBooleanOperation(IRBuilder2& irBuilder, const CHIRBinaryExprWrapper& binOp)
{
using GenerateFunc = std::function<llvm::Value*(llvm::IRBuilder<>&, llvm::Value*, llvm::Value*)>;
using OperatorKind = CHIR::ExprKind;
using namespace std::placeholders;
static const std::map<OperatorKind, GenerateFunc> mapForFloat = {
{OperatorKind::LT, std::bind(&IRBuilder2::CreateFCmpOLT, _1, _2, _3, "fcmpolt", nullptr)},
{OperatorKind::GT, std::bind(&IRBuilder2::CreateFCmpOGT, _1, _2, _3, "fcmpogt", nullptr)},
{OperatorKind::LE, std::bind(&IRBuilder2::CreateFCmpOLE, _1, _2, _3, "fcmpole", nullptr)},
{OperatorKind::GE, std::bind(&IRBuilder2::CreateFCmpOGE, _1, _2, _3, "fcmpoge", nullptr)},
{OperatorKind::EQUAL, std::bind(&IRBuilder2::CreateFCmpOEQ, _1, _2, _3, "fcmpoeq", nullptr)},
{OperatorKind::NOTEQUAL, std::bind(&IRBuilder2::CreateFCmpUNE, _1, _2, _3, "fcmpune", nullptr)},
};
static const std::map<OperatorKind, GenerateFunc> mapForUnsigned = {
{OperatorKind::LT, std::bind(&IRBuilder2::CreateICmpULT, _1, _2, _3, "icmpult")},
{OperatorKind::GT, std::bind(&IRBuilder2::CreateICmpUGT, _1, _2, _3, "icmpugt")},
{OperatorKind::LE, std::bind(&IRBuilder2::CreateICmpULE, _1, _2, _3, "icmpule")},
{OperatorKind::GE, std::bind(&IRBuilder2::CreateICmpUGE, _1, _2, _3, "icmpuge")},
{OperatorKind::EQUAL, std::bind(&IRBuilder2::CreateICmpEQ, _1, _2, _3, "icmpeq")},
{OperatorKind::NOTEQUAL, std::bind(&IRBuilder2::CreateICmpNE, _1, _2, _3, "icmpne")},
};
static const std::map<OperatorKind, GenerateFunc> mapForOthers = {
{OperatorKind::LT, std::bind(&IRBuilder2::CreateICmpSLT, _1, _2, _3, "icmpslt")},
{OperatorKind::GT, std::bind(&IRBuilder2::CreateICmpSGT, _1, _2, _3, "icmpsgt")},
{OperatorKind::LE, std::bind(&IRBuilder2::CreateICmpSLE, _1, _2, _3, "icmpsle")},
{OperatorKind::GE, std::bind(&IRBuilder2::CreateICmpSGE, _1, _2, _3, "icmpsge")},
{OperatorKind::EQUAL, std::bind(&IRBuilder2::CreateICmpEQ, _1, _2, _3, "icmpeq")},
{OperatorKind::NOTEQUAL, std::bind(&IRBuilder2::CreateICmpNE, _1, _2, _3, "icmpne")},
};
auto& cgMod = irBuilder.GetCGModule();
auto leftArg = binOp.GetLHSOperand();
auto leftArgTypeInfo = leftArg->GetType();
llvm::Value* valLeft = **(cgMod | leftArg);
llvm::Value* valRight = **(cgMod | binOp.GetRHSOperand());
CJC_NULLPTR_CHECK(valLeft);
CJC_NULLPTR_CHECK(valRight);
if (valLeft->getType()->isIntegerTy() && valRight->getType()->isIntegerTy() &&
valLeft->getType()->getIntegerBitWidth() != valRight->getType()->getIntegerBitWidth()) {
valLeft = irBuilder.CreateZExtOrTrunc(valLeft, valRight->getType());
}
if ((leftArgTypeInfo->IsUnit() || leftArgTypeInfo->IsNothing()) &&
(binOp.GetBinaryExprKind() == OperatorKind::EQUAL || binOp.GetBinaryExprKind() == OperatorKind::NOTEQUAL)) {
return binOp.GetBinaryExprKind() == OperatorKind::EQUAL ? irBuilder.getTrue() : irBuilder.getFalse();
}
std::map<OperatorKind, GenerateFunc> currentMap;
if (leftArgTypeInfo->IsFloat()) {
currentMap = mapForFloat;
} else if (leftArgTypeInfo->IsInteger() && !StaticCast<CHIR::IntType*>(leftArgTypeInfo)->IsSigned()) {
currentMap = mapForUnsigned;
} else {
currentMap = mapForOthers;
}
auto iter = std::as_const(currentMap).find(binOp.GetBinaryExprKind());
return iter->second(irBuilder, valLeft, valRight);
}
}
}