OLD | NEW |
---|---|
1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// | 1 //===- subzero/src/IceTargetLoweringARM32.cpp - ARM32 lowering ------------===// |
2 // | 2 // |
3 // The Subzero Code Generator | 3 // The Subzero Code Generator |
4 // | 4 // |
5 // This file is distributed under the University of Illinois Open Source | 5 // This file is distributed under the University of Illinois Open Source |
6 // License. See LICENSE.TXT for details. | 6 // License. See LICENSE.TXT for details. |
7 // | 7 // |
8 //===----------------------------------------------------------------------===// | 8 //===----------------------------------------------------------------------===// |
9 /// | 9 /// |
10 /// \file | 10 /// \file |
(...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
454 "Infinite-weight Variable has no register assigned"); | 454 "Infinite-weight Variable has no register assigned"); |
455 } | 455 } |
456 int32_t Offset = Var->getStackOffset(); | 456 int32_t Offset = Var->getStackOffset(); |
457 int32_t BaseRegNum = Var->getBaseRegNum(); | 457 int32_t BaseRegNum = Var->getBaseRegNum(); |
458 if (BaseRegNum == Variable::NoRegister) { | 458 if (BaseRegNum == Variable::NoRegister) { |
459 BaseRegNum = getFrameOrStackReg(); | 459 BaseRegNum = getFrameOrStackReg(); |
460 if (!hasFramePointer()) | 460 if (!hasFramePointer()) |
461 Offset += getStackAdjustment(); | 461 Offset += getStackAdjustment(); |
462 } | 462 } |
463 const Type VarTy = Var->getType(); | 463 const Type VarTy = Var->getType(); |
464 if (!isLegalVariableStackOffset(VarTy, Offset)) { | 464 if (!isLegalMemOffset(VarTy, Offset)) { |
465 llvm::report_fatal_error("Illegal stack offset"); | 465 llvm::report_fatal_error("Illegal stack offset"); |
466 } | 466 } |
467 Str << "[" << getRegName(BaseRegNum, VarTy); | 467 Str << "[" << getRegName(BaseRegNum, VarTy); |
468 if (Offset != 0) { | 468 if (Offset != 0) { |
469 Str << ", " << getConstantPrefix() << Offset; | 469 Str << ", " << getConstantPrefix() << Offset; |
470 } | 470 } |
471 Str << "]"; | 471 Str << "]"; |
472 } | 472 } |
473 | 473 |
474 bool TargetARM32::CallingConv::I64InRegs(std::pair<int32_t, int32_t> *Regs) { | 474 bool TargetARM32::CallingConv::I64InRegs(std::pair<int32_t, int32_t> *Regs) { |
(...skipping 461 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
936 Variable *RetValue = nullptr; | 936 Variable *RetValue = nullptr; |
937 if (RI->getSrcSize()) | 937 if (RI->getSrcSize()) |
938 RetValue = llvm::cast<Variable>(RI->getSrc(0)); | 938 RetValue = llvm::cast<Variable>(RI->getSrc(0)); |
939 _bundle_lock(); | 939 _bundle_lock(); |
940 _bic(LR, LR, RetMask); | 940 _bic(LR, LR, RetMask); |
941 _ret(LR, RetValue); | 941 _ret(LR, RetValue); |
942 _bundle_unlock(); | 942 _bundle_unlock(); |
943 RI->setDeleted(); | 943 RI->setDeleted(); |
944 } | 944 } |
945 | 945 |
946 bool TargetARM32::isLegalVariableStackOffset(Type Ty, int32_t Offset) const { | 946 bool TargetARM32::isLegalMemOffset(Type Ty, int32_t Offset) const { |
947 constexpr bool SignExt = false; | 947 constexpr bool ZeroExt = false; |
948 return OperandARM32Mem::canHoldOffset(Ty, SignExt, Offset); | 948 return OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset); |
949 } | 949 } |
950 | 950 |
951 StackVariable *TargetARM32::legalizeVariableSlot(Variable *Var, | 951 Variable *TargetARM32::newBaseRegister(int32_t OriginalOffset, |
952 int32_t StackAdjust, | 952 int32_t StackAdjust, |
953 Variable *OrigBaseReg) { | 953 Variable *OrigBaseReg) { |
954 int32_t Offset = Var->getStackOffset() + StackAdjust; | 954 int32_t Offset = OriginalOffset + StackAdjust; |
955 // Legalize will likely need a movw/movt combination, but if the top bits are | 955 // Legalize will likely need a movw/movt combination, but if the top bits are |
956 // all 0 from negating the offset and subtracting, we could use that instead. | 956 // all 0 from negating the offset and subtracting, we could use that instead. |
957 bool ShouldSub = (-Offset & 0xFFFF0000) == 0; | 957 bool ShouldSub = (-Offset & 0xFFFF0000) == 0; |
958 if (ShouldSub) | 958 if (ShouldSub) |
959 Offset = -Offset; | 959 Offset = -Offset; |
960 Operand *OffsetVal = legalize(Ctx->getConstantInt32(Offset), | 960 Operand *OffsetVal = legalize(Ctx->getConstantInt32(Offset), |
961 Legal_Reg | Legal_Flex, getReservedTmpReg()); | 961 Legal_Reg | Legal_Flex, getReservedTmpReg()); |
962 Variable *ScratchReg = makeReg(IceType_i32, getReservedTmpReg()); | 962 Variable *ScratchReg = makeReg(IceType_i32, getReservedTmpReg()); |
963 if (ShouldSub) | 963 if (ShouldSub) |
964 _sub(ScratchReg, OrigBaseReg, OffsetVal); | 964 _sub(ScratchReg, OrigBaseReg, OffsetVal); |
965 else | 965 else |
966 _add(ScratchReg, OrigBaseReg, OffsetVal); | 966 _add(ScratchReg, OrigBaseReg, OffsetVal); |
967 StackVariable *NewVar = Func->makeVariable<StackVariable>(stackSlotType()); | 967 return ScratchReg; |
968 NewVar->setMustNotHaveReg(); | 968 } |
969 NewVar->setBaseRegNum(ScratchReg->getRegNum()); | 969 |
970 constexpr int32_t NewOffset = 0; | 970 StackVariable *TargetARM32::legalizeStackSlot(Type Ty, int32_t Offset, |
971 NewVar->setStackOffset(NewOffset); | 971 int32_t StackAdjust, |
972 return NewVar; | 972 Variable *OrigBaseReg, |
973 Variable **NewBaseReg, | |
974 int32_t *NewBaseOffset) { | |
Karl
2015/11/06 21:11:01
Why not int32_t &NewBaseOffset?
John
2015/11/09 22:42:25
Because the method changes NewBaseOffset inside.
| |
975 if (*NewBaseReg == nullptr) { | |
976 *NewBaseReg = newBaseRegister(Offset, StackAdjust, OrigBaseReg); | |
977 *NewBaseOffset = Offset + StackAdjust; | |
978 } | |
979 | |
980 int32_t OffsetDiff = Offset + StackAdjust - *NewBaseOffset; | |
981 if (!isLegalMemOffset(Ty, OffsetDiff)) { | |
982 *NewBaseReg = newBaseRegister(Offset, StackAdjust, OrigBaseReg); | |
983 *NewBaseOffset = Offset + StackAdjust; | |
984 OffsetDiff = 0; | |
985 } | |
986 | |
987 StackVariable *NewDest = Func->makeVariable<StackVariable>(Ty); | |
988 NewDest->setMustNotHaveReg(); | |
989 NewDest->setBaseRegNum((*NewBaseReg)->getRegNum()); | |
990 NewDest->setStackOffset(OffsetDiff); | |
991 return NewDest; | |
992 } | |
993 | |
994 void TargetARM32::legalizeMovStackAddrImm(InstARM32Mov *MovInstr, | |
995 int32_t StackAdjust, | |
996 Variable *OrigBaseReg, | |
997 Variable **NewBaseReg, | |
998 int32_t *NewBaseOffset) { | |
999 Variable *Dest = MovInstr->getDest(); | |
1000 assert(Dest != nullptr); | |
1001 Type DestTy = Dest->getType(); | |
1002 assert(DestTy != IceType_i64); | |
1003 | |
1004 Operand *Src = MovInstr->getSrc(0); | |
1005 Type SrcTy = Src->getType(); | |
1006 assert(SrcTy != IceType_i64); | |
1007 | |
1008 if (MovInstr->isMultiDest() || MovInstr->isMultiSource()) | |
1009 return; | |
1010 | |
1011 bool Legalized = false; | |
1012 if (!Dest->hasReg()) { | |
1013 assert(llvm::cast<Variable>(Src)->hasReg()); | |
1014 const int32_t Offset = Dest->getStackOffset(); | |
1015 if (!isLegalMemOffset(DestTy, Offset + StackAdjust)) { | |
1016 Legalized = true; | |
1017 Dest = legalizeStackSlot(DestTy, Offset, StackAdjust, OrigBaseReg, | |
1018 NewBaseReg, NewBaseOffset); | |
1019 } | |
1020 } else if (auto *Var = llvm::dyn_cast<Variable>(Src)) { | |
1021 if (!Var->hasReg()) { | |
1022 const int32_t Offset = Var->getStackOffset(); | |
1023 if (!isLegalMemOffset(SrcTy, Offset + StackAdjust)) { | |
1024 Legalized = true; | |
1025 Src = legalizeStackSlot(SrcTy, Offset, StackAdjust, OrigBaseReg, | |
1026 NewBaseReg, NewBaseOffset); | |
1027 } | |
1028 } | |
1029 } else if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(Src)) { | |
1030 if (ConstantInteger32 *OffsetOp = Mem->getOffset()) { | |
1031 const int32_t Offset = OffsetOp->getValue(); | |
1032 if (!isLegalMemOffset(SrcTy, Offset + StackAdjust)) { | |
1033 assert(Mem->getBase()->hasReg()); | |
1034 assert(Mem->getBase()->getRegNum() == (int)getFrameOrStackReg()); | |
Jim Stichnoth
2015/11/08 20:05:51
int32_t for consistency
John
2015/11/09 22:42:24
Done.
| |
1035 Legalized = true; | |
1036 Src = legalizeStackSlot(SrcTy, Offset, StackAdjust, OrigBaseReg, | |
1037 NewBaseReg, NewBaseOffset); | |
1038 } | |
1039 } | |
1040 } | |
1041 | |
1042 if (Legalized) { | |
1043 _mov(Dest, Src); | |
1044 MovInstr->setDeleted(); | |
1045 } | |
973 } | 1046 } |
974 | 1047 |
975 void TargetARM32::legalizeStackSlots() { | 1048 void TargetARM32::legalizeStackSlots() { |
976 // If a stack variable's frame offset doesn't fit, convert from: | 1049 // If a stack variable's frame offset doesn't fit, convert from: |
977 // ldr X, OFF[SP] | 1050 // ldr X, OFF[SP] |
978 // to: | 1051 // to: |
979 // movw/movt TMP, OFF_PART | 1052 // movw/movt TMP, OFF_PART |
980 // add TMP, TMP, SP | 1053 // add TMP, TMP, SP |
981 // ldr X, OFF_MORE[TMP] | 1054 // ldr X, OFF_MORE[TMP] |
982 // | 1055 // |
983 // This is safe because we have reserved TMP, and add for ARM does not | 1056 // This is safe because we have reserved TMP, and add for ARM does not |
984 // clobber the flags register. | 1057 // clobber the flags register. |
985 Func->dump("Before legalizeStackSlots"); | 1058 Func->dump("Before legalizeStackSlots"); |
986 assert(hasComputedFrame()); | 1059 assert(hasComputedFrame()); |
987 // Early exit, if SpillAreaSizeBytes is really small. | 1060 // Early exit, if SpillAreaSizeBytes is really small. |
988 // TODO(jpp): this is not safe -- loads and stores of q registers can't have | 1061 // TODO(jpp): this is not safe -- loads and stores of q registers can't have |
989 // offsets. | 1062 // offsets. |
990 if (isLegalVariableStackOffset(IceType_v4i32, SpillAreaSizeBytes)) | 1063 if (isLegalMemOffset(IceType_v4i32, SpillAreaSizeBytes)) |
991 return; | 1064 return; |
992 Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg()); | 1065 Variable *OrigBaseReg = getPhysicalRegister(getFrameOrStackReg()); |
993 int32_t StackAdjust = 0; | 1066 int32_t StackAdjust = 0; |
994 // Do a fairly naive greedy clustering for now. Pick the first stack slot | 1067 // Do a fairly naive greedy clustering for now. Pick the first stack slot |
995 // that's out of bounds and make a new base reg using the architecture's temp | 1068 // that's out of bounds and make a new base reg using the architecture's temp |
996 // register. If that works for the next slot, then great. Otherwise, create a | 1069 // register. If that works for the next slot, then great. Otherwise, create a |
997 // new base register, clobbering the previous base register. Never share a | 1070 // new base register, clobbering the previous base register. Never share a |
998 // base reg across different basic blocks. This isn't ideal if local and | 1071 // base reg across different basic blocks. This isn't ideal if local and |
999 // multi-block variables are far apart and their references are interspersed. | 1072 // multi-block variables are far apart and their references are interspersed. |
1000 // It may help to be more coordinated about assign stack slot numbers and may | 1073 // It may help to be more coordinated about assign stack slot numbers and may |
1001 // help to assign smaller offsets to higher-weight variables so that they | 1074 // help to assign smaller offsets to higher-weight variables so that they |
1002 // don't depend on this legalization. | 1075 // don't depend on this legalization. |
1003 for (CfgNode *Node : Func->getNodes()) { | 1076 for (CfgNode *Node : Func->getNodes()) { |
1004 Context.init(Node); | 1077 Context.init(Node); |
1005 StackVariable *NewBaseReg = nullptr; | 1078 Variable *NewBaseReg = nullptr; |
1006 int32_t NewBaseOffset = 0; | 1079 int32_t NewBaseOffset = 0; |
1007 while (!Context.atEnd()) { | 1080 while (!Context.atEnd()) { |
1008 PostIncrLoweringContext PostIncrement(Context); | 1081 PostIncrLoweringContext PostIncrement(Context); |
1009 Inst *CurInstr = Context.getCur(); | 1082 Inst *CurInstr = Context.getCur(); |
1010 Variable *Dest = CurInstr->getDest(); | 1083 Variable *Dest = CurInstr->getDest(); |
1084 | |
1011 // Check if the previous NewBaseReg is clobbered, and reset if needed. | 1085 // Check if the previous NewBaseReg is clobbered, and reset if needed. |
1012 if ((Dest && NewBaseReg && Dest->hasReg() && | 1086 if ((Dest && NewBaseReg && Dest->hasReg() && |
1013 Dest->getRegNum() == NewBaseReg->getBaseRegNum()) || | 1087 Dest->getRegNum() == NewBaseReg->getBaseRegNum()) || |
1014 llvm::isa<InstFakeKill>(CurInstr)) { | 1088 llvm::isa<InstFakeKill>(CurInstr)) { |
1015 NewBaseReg = nullptr; | 1089 NewBaseReg = nullptr; |
1016 NewBaseOffset = 0; | 1090 NewBaseOffset = 0; |
1017 } | 1091 } |
1092 | |
1018 // The stack adjustment only matters if we are using SP instead of FP. | 1093 // The stack adjustment only matters if we are using SP instead of FP. |
1019 if (!hasFramePointer()) { | 1094 if (!hasFramePointer()) { |
1020 if (auto *AdjInst = llvm::dyn_cast<InstARM32AdjustStack>(CurInstr)) { | 1095 if (auto *AdjInst = llvm::dyn_cast<InstARM32AdjustStack>(CurInstr)) { |
1021 StackAdjust += AdjInst->getAmount(); | 1096 StackAdjust += AdjInst->getAmount(); |
1022 NewBaseOffset += AdjInst->getAmount(); | 1097 NewBaseOffset += AdjInst->getAmount(); |
1023 continue; | 1098 continue; |
1024 } | 1099 } |
1025 if (llvm::isa<InstARM32Call>(CurInstr)) { | 1100 if (llvm::isa<InstARM32Call>(CurInstr)) { |
1026 NewBaseOffset -= StackAdjust; | 1101 NewBaseOffset -= StackAdjust; |
1027 StackAdjust = 0; | 1102 StackAdjust = 0; |
1028 continue; | 1103 continue; |
1029 } | 1104 } |
1030 } | 1105 } |
1031 | 1106 |
1032 // For now, only Mov instructions can have stack variables. We need to | 1107 // The Lowering ensures that ldr and str always have legal Mem operands. |
1033 // know the type of instruction because we currently create a fresh one | 1108 // The only other instruction that may access memory is mov. |
1034 // to replace Dest/Source, rather than mutate in place. | |
1035 bool MayNeedOffsetRewrite = false; | |
1036 if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) { | 1109 if (auto *MovInstr = llvm::dyn_cast<InstARM32Mov>(CurInstr)) { |
1037 MayNeedOffsetRewrite = | 1110 legalizeMovStackAddrImm(MovInstr, StackAdjust, OrigBaseReg, &NewBaseReg, |
1038 !MovInstr->isMultiDest() && !MovInstr->isMultiSource(); | 1111 &NewBaseOffset); |
1039 } | |
1040 | |
1041 if (!MayNeedOffsetRewrite) { | |
1042 continue; | |
1043 } | |
1044 | |
1045 assert(Dest != nullptr); | |
1046 Type DestTy = Dest->getType(); | |
1047 assert(DestTy != IceType_i64); | |
1048 if (!Dest->hasReg()) { | |
1049 int32_t Offset = Dest->getStackOffset(); | |
1050 Offset += StackAdjust; | |
1051 if (!isLegalVariableStackOffset(DestTy, Offset)) { | |
1052 if (NewBaseReg) { | |
1053 int32_t OffsetDiff = Offset - NewBaseOffset; | |
1054 if (isLegalVariableStackOffset(DestTy, OffsetDiff)) { | |
1055 StackVariable *NewDest = | |
1056 Func->makeVariable<StackVariable>(stackSlotType()); | |
1057 NewDest->setMustNotHaveReg(); | |
1058 NewDest->setBaseRegNum(NewBaseReg->getBaseRegNum()); | |
1059 NewDest->setStackOffset(OffsetDiff); | |
1060 Variable *NewDestVar = NewDest; | |
1061 _mov(NewDestVar, CurInstr->getSrc(0)); | |
1062 CurInstr->setDeleted(); | |
1063 continue; | |
1064 } | |
1065 } | |
1066 StackVariable *LegalDest = | |
1067 legalizeVariableSlot(Dest, StackAdjust, OrigBaseReg); | |
1068 assert(LegalDest != Dest); | |
1069 Variable *LegalDestVar = LegalDest; | |
1070 _mov(LegalDestVar, CurInstr->getSrc(0)); | |
1071 CurInstr->setDeleted(); | |
1072 NewBaseReg = LegalDest; | |
1073 NewBaseOffset = Offset; | |
1074 continue; | |
1075 } | |
1076 } | |
1077 assert(CurInstr->getSrcSize() == 1); | |
1078 Variable *Var = llvm::dyn_cast<Variable>(CurInstr->getSrc(0)); | |
1079 if (Var && !Var->hasReg()) { | |
1080 Type VarTy = Var->getType(); | |
1081 int32_t Offset = Var->getStackOffset(); | |
1082 Offset += StackAdjust; | |
1083 if (!isLegalVariableStackOffset(VarTy, Offset)) { | |
1084 if (NewBaseReg) { | |
1085 int32_t OffsetDiff = Offset - NewBaseOffset; | |
1086 if (isLegalVariableStackOffset(VarTy, OffsetDiff)) { | |
1087 StackVariable *NewVar = | |
1088 Func->makeVariable<StackVariable>(stackSlotType()); | |
1089 NewVar->setMustNotHaveReg(); | |
1090 NewVar->setBaseRegNum(NewBaseReg->getBaseRegNum()); | |
1091 NewVar->setStackOffset(OffsetDiff); | |
1092 _mov(Dest, NewVar); | |
1093 CurInstr->setDeleted(); | |
1094 continue; | |
1095 } | |
1096 } | |
1097 StackVariable *LegalVar = | |
1098 legalizeVariableSlot(Var, StackAdjust, OrigBaseReg); | |
1099 assert(LegalVar != Var); | |
1100 _mov(Dest, LegalVar); | |
1101 CurInstr->setDeleted(); | |
1102 NewBaseReg = LegalVar; | |
1103 NewBaseOffset = Offset; | |
1104 continue; | |
1105 } | |
1106 } | 1112 } |
1107 } | 1113 } |
1108 } | 1114 } |
1109 } | 1115 } |
1110 | 1116 |
1111 Operand *TargetARM32::loOperand(Operand *Operand) { | 1117 Operand *TargetARM32::loOperand(Operand *Operand) { |
1112 assert(Operand->getType() == IceType_i64); | 1118 assert(Operand->getType() == IceType_i64); |
1113 if (Operand->getType() != IceType_i64) | 1119 if (Operand->getType() != IceType_i64) |
1114 return Operand; | 1120 return Operand; |
1115 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand)) | 1121 if (auto *Var64On32 = llvm::dyn_cast<Variable64On32>(Operand)) |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1160 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, NewBase, | 1166 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, NewBase, |
1161 Base, Four)); | 1167 Base, Four)); |
1162 return OperandARM32Mem::create(Func, SplitType, NewBase, Mem->getIndex(), | 1168 return OperandARM32Mem::create(Func, SplitType, NewBase, Mem->getIndex(), |
1163 Mem->getShiftOp(), Mem->getShiftAmt(), | 1169 Mem->getShiftOp(), Mem->getShiftAmt(), |
1164 Mem->getAddrMode()); | 1170 Mem->getAddrMode()); |
1165 } else { | 1171 } else { |
1166 Variable *Base = Mem->getBase(); | 1172 Variable *Base = Mem->getBase(); |
1167 ConstantInteger32 *Offset = Mem->getOffset(); | 1173 ConstantInteger32 *Offset = Mem->getOffset(); |
1168 assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4)); | 1174 assert(!Utils::WouldOverflowAdd(Offset->getValue(), 4)); |
1169 int32_t NextOffsetVal = Offset->getValue() + 4; | 1175 int32_t NextOffsetVal = Offset->getValue() + 4; |
1170 const bool SignExt = false; | 1176 const bool ZeroExt = false; |
Karl
2015/11/06 21:11:01
constexpr?
John
2015/11/09 22:42:25
Done.
| |
1171 if (!OperandARM32Mem::canHoldOffset(SplitType, SignExt, NextOffsetVal)) { | 1177 if (!OperandARM32Mem::canHoldOffset(SplitType, ZeroExt, NextOffsetVal)) { |
1172 // We have to make a temp variable and add 4 to either Base or Offset. | 1178 // We have to make a temp variable and add 4 to either Base or Offset. |
1173 // If we add 4 to Offset, this will convert a non-RegReg addressing | 1179 // If we add 4 to Offset, this will convert a non-RegReg addressing |
1174 // mode into a RegReg addressing mode. Since NaCl sandboxing disallows | 1180 // mode into a RegReg addressing mode. Since NaCl sandboxing disallows |
1175 // RegReg addressing modes, prefer adding to base and replacing | 1181 // RegReg addressing modes, prefer adding to base and replacing |
1176 // instead. Thus we leave the old offset alone. | 1182 // instead. Thus we leave the old offset alone. |
1177 Constant *Four = Ctx->getConstantInt32(4); | 1183 Constant *Four = Ctx->getConstantInt32(4); |
1178 Variable *NewBase = Func->makeVariable(Base->getType()); | 1184 Variable *NewBase = Func->makeVariable(Base->getType()); |
1179 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, | 1185 lowerArithmetic(InstArithmetic::create(Func, InstArithmetic::Add, |
1180 NewBase, Base, Four)); | 1186 NewBase, Base, Four)); |
1181 Base = NewBase; | 1187 Base = NewBase; |
(...skipping 626 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1808 if (Instr->isUnconditional()) { | 1814 if (Instr->isUnconditional()) { |
1809 _br(Instr->getTargetUnconditional()); | 1815 _br(Instr->getTargetUnconditional()); |
1810 return; | 1816 return; |
1811 } | 1817 } |
1812 Operand *Cond = Instr->getCondition(); | 1818 Operand *Cond = Instr->getCondition(); |
1813 | 1819 |
1814 CondARM32::Cond BrCondTrue0 = CondARM32::NE; | 1820 CondARM32::Cond BrCondTrue0 = CondARM32::NE; |
1815 CondARM32::Cond BrCondTrue1 = CondARM32::kNone; | 1821 CondARM32::Cond BrCondTrue1 = CondARM32::kNone; |
1816 CondARM32::Cond BrCondFalse = CondARM32::kNone; | 1822 CondARM32::Cond BrCondFalse = CondARM32::kNone; |
1817 if (!_mov_i1_to_flags(Cond, &BrCondTrue0, &BrCondTrue1, &BrCondFalse)) { | 1823 if (!_mov_i1_to_flags(Cond, &BrCondTrue0, &BrCondTrue1, &BrCondFalse)) { |
1818 // "Cond" was not fold. | 1824 // "Cond" was not folded. |
1819 Type Ty = Cond->getType(); | 1825 Type Ty = Cond->getType(); |
1820 Variable *Src0R = legalizeToReg(Cond); | 1826 Variable *Src0R = legalizeToReg(Cond); |
1821 assert(Ty == IceType_i1); | 1827 assert(Ty == IceType_i1); |
1822 if (Ty != IceType_i32) | 1828 if (Ty != IceType_i32) |
1823 _uxt(Src0R, Src0R); | 1829 _uxt(Src0R, Src0R); |
1824 Constant *_0 = Ctx->getConstantZero(IceType_i32); | 1830 Constant *_0 = Ctx->getConstantZero(IceType_i32); |
1825 _cmp(Src0R, _0); | 1831 _cmp(Src0R, _0); |
1826 BrCondTrue0 = CondARM32::NE; | 1832 BrCondTrue0 = CondARM32::NE; |
1827 } | 1833 } |
1828 | 1834 |
(...skipping 1535 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3364 Type Ty = Load->getDest()->getType(); | 3370 Type Ty = Load->getDest()->getType(); |
3365 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty); | 3371 Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty); |
3366 Variable *DestLoad = Load->getDest(); | 3372 Variable *DestLoad = Load->getDest(); |
3367 | 3373 |
3368 // TODO(jvoung): handled folding opportunities. Sign and zero extension can | 3374 // TODO(jvoung): handled folding opportunities. Sign and zero extension can |
3369 // be folded into a load. | 3375 // be folded into a load. |
3370 InstAssign *Assign = InstAssign::create(Func, DestLoad, Src0); | 3376 InstAssign *Assign = InstAssign::create(Func, DestLoad, Src0); |
3371 lowerAssign(Assign); | 3377 lowerAssign(Assign); |
3372 } | 3378 } |
3373 | 3379 |
3374 void TargetARM32::doAddressOptLoad() {} | 3380 namespace { |
3381 void dumpAddressOpt(const Cfg *Func, const Variable *Base, int32_t Offset, | |
3382 const Variable *OffsetReg, int16_t OffsetRegShamt, | |
Jim Stichnoth
2015/11/08 20:05:51
tiny nit - OffsetRegShAmt ?
(here and below)
John
2015/11/09 22:42:24
Done.
| |
3383 const Inst *Reason) { | |
3384 if (!BuildDefs::dump()) | |
3385 return; | |
3386 if (!Func->isVerbose(IceV_AddrOpt)) | |
3387 return; | |
3388 OstreamLocker _(Func->getContext()); | |
3389 Ostream &Str = Func->getContext()->getStrDump(); | |
3390 Str << "Instruction: "; | |
3391 Reason->dumpDecorated(Func); | |
3392 Str << " results in Base="; | |
3393 if (Base) | |
3394 Base->dump(Func); | |
3395 else | |
3396 Str << "<null>"; | |
3397 Str << ", OffsetReg="; | |
3398 if (OffsetReg) | |
3399 OffsetReg->dump(Func); | |
3400 else | |
3401 Str << "<null>"; | |
3402 Str << ", Shift=" << OffsetRegShamt << ", Offset=" << Offset << "\n"; | |
3403 } | |
3404 | |
3405 bool matchAssign(const VariablesMetadata *VMetadata, Variable **Var, | |
3406 int32_t *Offset, const Inst **Reason) { | |
3407 // Var originates from Var=SrcVar ==> set Var:=SrcVar | |
3408 if (*Var == nullptr) | |
3409 return false; | |
3410 const Inst *VarAssign = VMetadata->getSingleDefinition(*Var); | |
3411 if (!VarAssign) | |
3412 return false; | |
3413 assert(!VMetadata->isMultiDef(*Var)); | |
3414 if (!llvm::isa<InstAssign>(VarAssign)) | |
3415 return false; | |
3416 | |
3417 Operand *SrcOp = VarAssign->getSrc(0); | |
3418 assert(SrcOp); | |
Jim Stichnoth
2015/11/08 20:05:50
This assert is a relic of the early days when mayb
John
2015/11/09 22:42:25
Done.
| |
3419 if (auto *SrcVar = llvm::dyn_cast<Variable>(SrcOp)) { | |
3420 if (!VMetadata->isMultiDef(SrcVar) || | |
3421 // TODO: ensure SrcVar stays single-BB | |
3422 false) { | |
3423 return false; | |
3424 *Var = SrcVar; | |
Jim Stichnoth
2015/11/08 20:05:51
this statement is unreachable
John
2015/11/09 22:42:24
Done.
| |
3425 } else if (auto *Const = llvm::dyn_cast<ConstantInteger32>(SrcOp)) { | |
Jim Stichnoth
2015/11/08 20:05:51
Don't use "else if" if the previous branch is real
John
2015/11/09 22:42:24
N/A.
| |
3426 if (false) | |
3427 return false; | |
Jim Stichnoth
2015/11/08 20:05:51
Why not return true?
:)
John
2015/11/09 22:42:24
I really don't know how high I was here.
| |
3428 int32_t MoreOffset = Const->getValue(); | |
3429 int32_t NewOffset = MoreOffset + *Offset; | |
3430 if (Utils::WouldOverflowAdd(*Offset, MoreOffset)) | |
3431 return false; | |
3432 *Var = nullptr; | |
3433 *Offset += NewOffset; | |
3434 } | |
3435 | |
3436 *Reason = VarAssign; | |
3437 return true; | |
3438 } | |
3439 | |
3440 return false; | |
3441 } | |
3442 | |
3443 bool isAddOrSub(const Inst *Inst, InstArithmetic::OpKind *Kind) { | |
3444 if (auto *Arith = llvm::dyn_cast_or_null<const InstArithmetic>(Inst)) { | |
Jim Stichnoth
2015/11/08 20:05:51
Can you just use dyn_cast? It looks like Inst can
John
2015/11/09 22:42:24
Done.
| |
3445 switch (Arith->getOp()) { | |
3446 default: | |
3447 return false; | |
3448 case InstArithmetic::Add: | |
3449 case InstArithmetic::Sub: | |
3450 *Kind = Arith->getOp(); | |
3451 return true; | |
3452 } | |
3453 } | |
3454 return false; | |
3455 } | |
3456 | |
3457 bool matchCombinedBaseIndex(const VariablesMetadata *VMetadata, Variable **Base, | |
3458 Variable **OffsetReg, int32_t OffsetRegShamt, | |
3459 const Inst **Reason) { | |
3460 // OffsetReg==nullptr && Base is Base=Var1+Var2 ==> | |
3461 // set Base=Var1, OffsetReg=Var2, Shift=0 | |
3462 if (*Base == nullptr) | |
3463 return false; | |
3464 if (*OffsetReg != nullptr) | |
3465 return false; | |
3466 assert(OffsetRegShamt == 0); | |
3467 const Inst *BaseInst = VMetadata->getSingleDefinition(*Base); | |
3468 if (BaseInst == nullptr) | |
3469 return false; | |
3470 assert(!VMetadata->isMultiDef(*Base)); | |
3471 if (BaseInst->getSrcSize() < 2) | |
3472 return false; | |
3473 auto *Var1 = llvm::dyn_cast<Variable>(BaseInst->getSrc(0)); | |
3474 if (!Var1) | |
3475 return false; | |
3476 if (VMetadata->isMultiDef(Var1)) | |
3477 return false; | |
3478 auto *Var2 = llvm::dyn_cast<Variable>(BaseInst->getSrc(1)); | |
3479 if (!Var2) | |
3480 return false; | |
3481 if (VMetadata->isMultiDef(Var2)) | |
3482 return false; | |
3483 InstArithmetic::OpKind _; | |
3484 if (!isAddOrSub(BaseInst, &_) || | |
3485 // TODO: ensure Var1 and Var2 stay single-BB | |
3486 false) | |
3487 return false; | |
3488 *Base = Var1; | |
3489 *OffsetReg = Var2; | |
3490 // OffsetRegShamt is already 0. | |
3491 *Reason = BaseInst; | |
3492 return true; | |
3493 } | |
3494 | |
3495 bool matchShiftedOffsetReg(const VariablesMetadata *VMetadata, | |
3496 Variable **OffsetReg, OperandARM32::ShiftKind *Kind, | |
3497 int32_t *OffsetRegShamt, const Inst **Reason) { | |
3498 // OffsetReg is OffsetReg=Var*Const && log2(Const)+Shift<=32 ==> | |
3499 // OffsetReg=Var, Shift+=log2(Const) | |
3500 // OffsetReg is OffsetReg=Var<<Const && Const+Shift<=32 ==> | |
3501 // OffsetReg=Var, Shift+=Const | |
3502 // OffsetReg is OffsetReg=Var>>Const && Const-Shift>=-32 ==> | |
3503 // OffsetReg=Var, Shift-=Const | |
3504 OperandARM32::ShiftKind NewShiftKind = OperandARM32::kNoShift; | |
3505 if (*OffsetReg == nullptr) | |
3506 return false; | |
3507 auto *IndexInst = VMetadata->getSingleDefinition(*OffsetReg); | |
3508 if (IndexInst == nullptr) | |
3509 return false; | |
3510 assert(!VMetadata->isMultiDef(*OffsetReg)); | |
3511 if (IndexInst->getSrcSize() < 2) | |
3512 return false; | |
3513 auto *ArithInst = llvm::dyn_cast<InstArithmetic>(IndexInst); | |
3514 if (ArithInst == nullptr) | |
3515 return false; | |
3516 auto *Var = llvm::dyn_cast<Variable>(ArithInst->getSrc(0)); | |
3517 if (Var == nullptr) | |
3518 return false; | |
3519 auto *Const = llvm::dyn_cast<ConstantInteger32>(ArithInst->getSrc(1)); | |
3520 if (Const == nullptr) { | |
3521 assert(!llvm::isa<ConstantInteger32>(ArithInst->getSrc(0))); | |
3522 return false; | |
3523 } | |
3524 if (VMetadata->isMultiDef(Var) || Const->getType() != IceType_i32) | |
3525 return false; | |
3526 | |
3527 uint32_t NewShamt = -1; | |
3528 switch (ArithInst->getOp()) { | |
3529 default: | |
3530 return false; | |
3531 case InstArithmetic::Shl: { | |
3532 NewShiftKind = OperandARM32::LSL; | |
3533 NewShamt = Const->getValue(); | |
3534 if (NewShamt > 31) | |
3535 return false; | |
3536 } break; | |
3537 case InstArithmetic::Lshr: { | |
3538 NewShiftKind = OperandARM32::LSR; | |
3539 NewShamt = Const->getValue(); | |
3540 if (NewShamt > 31) | |
3541 return false; | |
3542 } break; | |
3543 case InstArithmetic::Ashr: { | |
3544 NewShiftKind = OperandARM32::ASR; | |
3545 NewShamt = Const->getValue(); | |
3546 if (NewShamt > 31) | |
3547 return false; | |
3548 } break; | |
3549 case InstArithmetic::Udiv: | |
3550 case InstArithmetic::Mul: { | |
3551 const uint32_t UnsignedConst = Const->getValue(); | |
3552 NewShamt = llvm::findFirstSet(UnsignedConst); | |
3553 if (NewShamt != llvm::findLastSet(UnsignedConst)) { | |
3554 // First bit set is not the same as the last bit set, so Const is not | |
3555 // a power of 2. | |
3556 return false; | |
3557 } | |
3558 NewShiftKind = ArithInst->getOp() == InstArithmetic::Udiv | |
3559 ? OperandARM32::LSR | |
3560 : OperandARM32::LSL; | |
3561 } break; | |
3562 } | |
3563 // Allowed "transitions": | |
3564 // kNoShift -> * iff NewShamt < 31 | |
3565 // LSL -> LSL iff NewShamt + OffsetRegShamt < 31 | |
3566 // LSR -> LSR iff NewShamt + OffsetRegShamt < 31 | |
3567 // ASR -> ASR iff NewShamt + OffsetRegShamt < 31 | |
3568 if (*Kind != OperandARM32::kNoShift && *Kind != NewShiftKind) { | |
3569 return false; | |
3570 } | |
3571 const int32_t NewOffsetRegShamt = *OffsetRegShamt + NewShamt; | |
3572 if (NewOffsetRegShamt > 31) | |
3573 return false; | |
3574 *OffsetReg = Var; | |
3575 *OffsetRegShamt = NewOffsetRegShamt; | |
3576 *Kind = NewShiftKind; | |
3577 *Reason = IndexInst; | |
3578 return true; | |
3579 } | |
3580 | |
3581 bool matchOffsetBase(const VariablesMetadata *VMetadata, Variable **Base, | |
3582 int32_t *Offset, const Inst **Reason) { | |
3583 // Base is Base=Var+Const || Base is Base=Const+Var ==> | |
3584 // set Base=Var, Offset+=Const | |
3585 // Base is Base=Var-Const ==> | |
3586 // set Base=Var, Offset-=Const | |
3587 if (*Base == nullptr) | |
3588 return false; | |
3589 const Inst *BaseInst = VMetadata->getSingleDefinition(*Base); | |
3590 if (BaseInst == nullptr) { | |
3591 return false; | |
3592 } | |
3593 assert(!VMetadata->isMultiDef(*Base)); | |
3594 | |
3595 auto *ArithInst = llvm::dyn_cast<const InstArithmetic>(BaseInst); | |
3596 if (ArithInst == nullptr) | |
3597 return false; | |
3598 InstArithmetic::OpKind Kind; | |
3599 if (!isAddOrSub(ArithInst, &Kind)) | |
3600 return false; | |
3601 bool IsAdd = Kind == InstArithmetic::Add; | |
3602 Operand *Src0 = ArithInst->getSrc(0); | |
3603 Operand *Src1 = ArithInst->getSrc(1); | |
3604 auto *Var0 = llvm::dyn_cast<Variable>(Src0); | |
3605 auto *Var1 = llvm::dyn_cast<Variable>(Src1); | |
3606 auto *Const0 = llvm::dyn_cast<ConstantInteger32>(Src0); | |
3607 auto *Const1 = llvm::dyn_cast<ConstantInteger32>(Src1); | |
3608 Variable *NewBase = nullptr; | |
3609 int32_t NewOffset = *Offset; | |
3610 | |
3611 if (Var0 == nullptr && Const0 == nullptr) { | |
3612 assert(llvm::isa<ConstantRelocatable>(Src0)); | |
3613 return false; | |
3614 } | |
3615 | |
3616 if (Var1 == nullptr && Const1 == nullptr) { | |
3617 assert(llvm::isa<ConstantRelocatable>(Src1)); | |
3618 return false; | |
3619 } | |
3620 | |
3621 if (Var0 && Var1) | |
3622 // TODO(jpp): merge base/index splitting into here. | |
3623 return false; | |
3624 if (!IsAdd && Var1) | |
3625 return false; | |
3626 if (Var0) | |
3627 NewBase = Var0; | |
3628 else if (Var1) | |
3629 NewBase = Var1; | |
3630 // Compute the updated constant offset. | |
3631 if (Const0) { | |
3632 int32_t MoreOffset = IsAdd ? Const0->getValue() : -Const0->getValue(); | |
3633 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) | |
3634 return false; | |
3635 NewOffset += MoreOffset; | |
3636 } | |
3637 if (Const1) { | |
3638 int32_t MoreOffset = IsAdd ? Const1->getValue() : -Const1->getValue(); | |
3639 if (Utils::WouldOverflowAdd(NewOffset, MoreOffset)) | |
3640 return false; | |
3641 NewOffset += MoreOffset; | |
3642 } | |
3643 | |
3644 // Update the computed address parameters once we are sure optimization | |
3645 // is valid. | |
3646 *Base = NewBase; | |
3647 *Offset = NewOffset; | |
3648 *Reason = BaseInst; | |
3649 return true; | |
3650 } | |
3651 } // end of anonymous namespace | |
3652 | |
3653 // ARM32 address modes: | |
3654 // ld/st i[8|16|32]: [reg], [reg +/- imm12], [pc +/- imm12], | |
3655 // [reg +/- reg << shamt5] | |
3656 // ld/st f[32|64] : [reg], [reg +/- imm8] , [pc +/- imm8] | |
3657 // ld/st vectors : [reg] | |
3658 // | |
3659 // For now, we don't handle address modes with Relocatables. | |
3660 namespace { | |
3661 // MemTraits contains per-type valid address mode information. | |
3662 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ | |
3663 static_assert(!(shaddr) || rraddr, "Check ICETYPEARM32_TABLE::" #tag); | |
3664 ICETYPEARM32_TABLE | |
3665 #undef X | |
3666 | |
3667 static const struct { | |
3668 int32_t ValidImmMask; | |
3669 bool CanHaveImm; | |
3670 bool CanHaveIndex; | |
3671 bool CanHaveShiftedIndex; | |
3672 } MemTraits[] = { | |
3673 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr, shaddr) \ | |
3674 { (1 << ubits) - 1, (ubits) > 0, rraddr, shaddr, } \ | |
3675 , | |
3676 ICETYPEARM32_TABLE | |
3677 #undef X | |
3678 }; | |
3679 static constexpr SizeT MemTraitsSize = llvm::array_lengthof(MemTraits); | |
3680 } // end of anonymous namespace | |
3681 | |
3682 OperandARM32Mem *TargetARM32::formAddressingMode(Type Ty, Cfg *Func, | |
3683 const Inst *LdSt, | |
3684 Operand *Base) { | |
3685 assert(Base != nullptr); | |
3686 int32_t OffsetImm = 0; | |
3687 Variable *OffsetReg = nullptr; | |
3688 int32_t OffsetRegShamt = 0; | |
3689 OperandARM32::ShiftKind ShiftKind = OperandARM32::kNoShift; | |
3690 | |
3691 Func->resetCurrentNode(); | |
3692 if (Func->isVerbose(IceV_AddrOpt)) { | |
3693 OstreamLocker L(Func->getContext()); | |
Jim Stichnoth
2015/11/08 20:05:51
Earlier you used "OstreamLocker _(...);"
John
2015/11/09 22:42:24
Changes everywhere.
| |
3694 Ostream &Str = Func->getContext()->getStrDump(); | |
3695 Str << "\nAddress mode formation:\t"; | |
3696 LdSt->dumpDecorated(Func); | |
3697 } | |
3698 | |
3699 if (isVectorType(Ty)) | |
3700 // vector loads and stores do not allow offsets, and only support the | |
3701 // "[reg]" addressing mode (the other supported modes are write back.) | |
3702 return nullptr; | |
3703 | |
3704 auto *BaseVar = llvm::dyn_cast<Variable>(Base); | |
3705 if (BaseVar == nullptr) | |
3706 return nullptr; | |
3707 | |
3708 assert(Ty < MemTraitsSize); | |
3709 auto *TypeTraits = &MemTraits[Ty]; | |
3710 const bool CanHaveIndex = TypeTraits->CanHaveIndex; | |
3711 const bool CanHaveShiftedIndex = TypeTraits->CanHaveShiftedIndex; | |
3712 const bool CanHaveImm = TypeTraits->CanHaveImm; | |
3713 const int32_t ValidImmMask = TypeTraits->ValidImmMask; | |
3714 assert(!CanHaveImm || ValidImmMask >= 0); | |
3715 | |
3716 const VariablesMetadata *VMetadata = Func->getVMetadata(); | |
3717 const Inst *Reason = nullptr; | |
3718 | |
3719 do { | |
3720 if (Reason != nullptr) { | |
3721 dumpAddressOpt(Func, BaseVar, OffsetImm, OffsetReg, OffsetRegShamt, | |
3722 Reason); | |
3723 Reason = nullptr; | |
3724 } | |
3725 | |
3726 if (matchAssign(VMetadata, &BaseVar, &OffsetImm, &Reason)) { | |
3727 continue; | |
3728 } | |
3729 | |
3730 if (CanHaveIndex && | |
3731 matchAssign(VMetadata, &OffsetReg, &OffsetImm, &Reason)) { | |
3732 continue; | |
3733 } | |
3734 | |
3735 if (CanHaveIndex && matchCombinedBaseIndex(VMetadata, &BaseVar, &OffsetReg, | |
3736 OffsetRegShamt, &Reason)) { | |
3737 continue; | |
3738 } | |
3739 | |
3740 if (CanHaveShiftedIndex) { | |
3741 if (matchShiftedOffsetReg(VMetadata, &OffsetReg, &ShiftKind, | |
3742 &OffsetRegShamt, &Reason)) { | |
3743 continue; | |
3744 } | |
3745 | |
3746 if ((OffsetRegShamt == 0) && | |
3747 matchShiftedOffsetReg(VMetadata, &BaseVar, &ShiftKind, | |
3748 &OffsetRegShamt, &Reason)) { | |
3749 std::swap(BaseVar, OffsetReg); | |
3750 continue; | |
3751 } | |
3752 } | |
3753 | |
3754 if (matchOffsetBase(VMetadata, &BaseVar, &OffsetImm, &Reason)) { | |
3755 continue; | |
3756 } | |
3757 } while (Reason); | |
3758 | |
3759 if (BaseVar == nullptr) { | |
3760 // [OffsetReg{, LSL Shamt}{, #OffsetImm}] is not legal in ARM, so we have to | |
3761 // legalize the addressing mode to [BaseReg, OffsetReg{, LSL Shamt}]. | |
3762 // Instead of a zeroed BaseReg, we initialize it with OffsetImm: | |
3763 // | |
3764 // [OffsetReg{, LSL Shamt}{, #OffsetImm}] -> | |
3765 // mov BaseReg, #OffsetImm | |
3766 // use of [BaseReg, OffsetReg{, LSL Shamt}] | |
3767 // | |
3768 static constexpr Type PointerType = IceType_i32; | |
3769 BaseVar = makeReg(PointerType); | |
3770 Context.insert( | |
3771 InstAssign::create(Func, BaseVar, Ctx->getConstantInt32(OffsetImm))); | |
3772 OffsetImm = 0; | |
3773 } else if (OffsetImm != 0) { | |
3774 // ARM Ldr/Str instructions have limited range immediates. The formation | |
3775 // loop above materialized an Immediate carelessly, so we ensure the | |
3776 // generated offset is sane. | |
3777 const int32_t PositiveOffset = OffsetImm > 0 ? OffsetImm : -OffsetImm; | |
3778 const InstArithmetic::OpKind Op = | |
3779 OffsetImm > 0 ? InstArithmetic::Add : InstArithmetic::Sub; | |
3780 | |
3781 if (!CanHaveImm || !isLegalMemOffset(Ty, OffsetImm) || | |
3782 OffsetReg != nullptr) { | |
3783 if (OffsetReg == nullptr) { | |
3784 // We formed a [Base, #const] addressing mode which is not encodable in | |
3785 // ARM. There is little point in forming an address mode now if we don't | |
3786 // have an offset. Effectively, we would end up with something like | |
3787 // | |
3788 // [Base, #const] -> add T, Base, #const | |
3789 // use of [T] | |
3790 // | |
3791 // Which is exactly what we already have. So we just bite the bullet | |
3792 // here and don't form any address mode. | |
3793 return nullptr; | |
3794 } | |
3795 // We formed [Base, Offset {, LSL Amnt}, #const]. Oops. Legalize it to | |
3796 // | |
3797 // [Base, Offset, {LSL amount}, #const] -> | |
3798 // add T, Base, #const | |
3799 // use of [T, Offset {, LSL amount}] | |
3800 static constexpr Type PointerType = IceType_i32; | |
Jim Stichnoth
2015/11/08 20:05:51
Can you use the existing getPointerType() instead?
John
2015/11/09 22:42:24
Then it is no longer a constexpr. :(
Jim Stichnoth
2015/11/09 22:47:49
Then why did you subsequently change it to "const"
John
2015/11/09 22:52:30
Done.
| |
3801 Variable *T = makeReg(PointerType); | |
3802 Context.insert(InstArithmetic::create( | |
3803 Func, Op, T, BaseVar, Ctx->getConstantInt32(PositiveOffset))); | |
3804 BaseVar = T; | |
3805 OffsetImm = 0; | |
3806 } | |
3807 } | |
3808 | |
3809 assert(BaseVar != nullptr); | |
3810 assert(OffsetImm == 0 || OffsetReg == nullptr); | |
3811 assert(OffsetReg == nullptr || CanHaveIndex); | |
3812 assert(OffsetImm < 0 ? (ValidImmMask & -OffsetImm) == -OffsetImm | |
3813 : (ValidImmMask & OffsetImm) == OffsetImm); | |
3814 | |
3815 if (OffsetReg != nullptr) { | |
3816 return OperandARM32Mem::create(Func, Ty, BaseVar, OffsetReg, ShiftKind, | |
3817 OffsetRegShamt); | |
3818 } | |
3819 | |
3820 return OperandARM32Mem::create( | |
3821 Func, Ty, BaseVar, | |
3822 llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(OffsetImm))); | |
3823 } | |
3824 | |
3825 void TargetARM32::doAddressOptLoad() { | |
3826 Inst *Instr = Context.getCur(); | |
3827 assert(llvm::isa<InstLoad>(Instr)); | |
3828 Variable *Dest = Instr->getDest(); | |
3829 Operand *Addr = Instr->getSrc(0); | |
3830 if (OperandARM32Mem *Mem = | |
3831 formAddressingMode(Dest->getType(), Func, Instr, Addr)) { | |
3832 Instr->setDeleted(); | |
3833 Context.insert(InstLoad::create(Func, Dest, Mem)); | |
3834 } | |
3835 } | |
3375 | 3836 |
3376 void TargetARM32::randomlyInsertNop(float Probability, | 3837 void TargetARM32::randomlyInsertNop(float Probability, |
3377 RandomNumberGenerator &RNG) { | 3838 RandomNumberGenerator &RNG) { |
3378 RandomNumberGeneratorWrapper RNGW(RNG); | 3839 RandomNumberGeneratorWrapper RNGW(RNG); |
3379 if (RNGW.getTrueWithProbability(Probability)) { | 3840 if (RNGW.getTrueWithProbability(Probability)) { |
3380 UnimplementedError(Func->getContext()->getFlags()); | 3841 UnimplementedError(Func->getContext()->getFlags()); |
3381 } | 3842 } |
3382 } | 3843 } |
3383 | 3844 |
3384 void TargetARM32::lowerPhi(const InstPhi * /*Inst*/) { | 3845 void TargetARM32::lowerPhi(const InstPhi * /*Inst*/) { |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3565 Variable *ValueHi = legalizeToReg(hiOperand(Value)); | 4026 Variable *ValueHi = legalizeToReg(hiOperand(Value)); |
3566 Variable *ValueLo = legalizeToReg(loOperand(Value)); | 4027 Variable *ValueLo = legalizeToReg(loOperand(Value)); |
3567 _str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr))); | 4028 _str(ValueHi, llvm::cast<OperandARM32Mem>(hiOperand(NewAddr))); |
3568 _str(ValueLo, llvm::cast<OperandARM32Mem>(loOperand(NewAddr))); | 4029 _str(ValueLo, llvm::cast<OperandARM32Mem>(loOperand(NewAddr))); |
3569 } else { | 4030 } else { |
3570 Variable *ValueR = legalizeToReg(Value); | 4031 Variable *ValueR = legalizeToReg(Value); |
3571 _str(ValueR, NewAddr); | 4032 _str(ValueR, NewAddr); |
3572 } | 4033 } |
3573 } | 4034 } |
3574 | 4035 |
3575 void TargetARM32::doAddressOptStore() {} | 4036 void TargetARM32::doAddressOptStore() { |
4037 Inst *Instr = Context.getCur(); | |
4038 assert(llvm::isa<InstStore>(Instr)); | |
4039 Operand *Src = Instr->getSrc(0); | |
4040 Operand *Addr = Instr->getSrc(1); | |
4041 if (OperandARM32Mem *Mem = | |
4042 formAddressingMode(Src->getType(), Func, Instr, Addr)) { | |
4043 Instr->setDeleted(); | |
4044 Context.insert(InstStore::create(Func, Src, Mem)); | |
4045 } | |
4046 } | |
3576 | 4047 |
3577 void TargetARM32::lowerSwitch(const InstSwitch *Inst) { | 4048 void TargetARM32::lowerSwitch(const InstSwitch *Inst) { |
3578 // This implements the most naive possible lowering. | 4049 // This implements the most naive possible lowering. |
3579 // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default | 4050 // cmp a,val[0]; jeq label[0]; cmp a,val[1]; jeq label[1]; ... jmp default |
3580 Operand *Src0 = Inst->getComparison(); | 4051 Operand *Src0 = Inst->getComparison(); |
3581 SizeT NumCases = Inst->getNumCases(); | 4052 SizeT NumCases = Inst->getNumCases(); |
3582 if (Src0->getType() == IceType_i64) { | 4053 if (Src0->getType() == IceType_i64) { |
3583 Src0 = legalizeUndef(Src0); | 4054 Src0 = legalizeUndef(Src0); |
3584 Variable *Src0Lo = legalizeToReg(loOperand(Src0)); | 4055 Variable *Src0Lo = legalizeToReg(loOperand(Src0)); |
3585 Variable *Src0Hi = legalizeToReg(hiOperand(Src0)); | 4056 Variable *Src0Hi = legalizeToReg(hiOperand(Src0)); |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3662 } | 4133 } |
3663 } | 4134 } |
3664 } | 4135 } |
3665 } | 4136 } |
3666 | 4137 |
3667 // Go through the various types of operands: OperandARM32Mem, | 4138 // Go through the various types of operands: OperandARM32Mem, |
3668 // OperandARM32Flex, Constant, and Variable. Given the above assertion, if | 4139 // OperandARM32Flex, Constant, and Variable. Given the above assertion, if |
3669 // type of operand is not legal (e.g., OperandARM32Mem and !Legal_Mem), we | 4140 // type of operand is not legal (e.g., OperandARM32Mem and !Legal_Mem), we |
3670 // can always copy to a register. | 4141 // can always copy to a register. |
3671 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(From)) { | 4142 if (auto *Mem = llvm::dyn_cast<OperandARM32Mem>(From)) { |
3672 static const struct { | |
3673 bool CanHaveOffset; | |
3674 bool CanHaveIndex; | |
3675 } MemTraits[] = { | |
3676 #define X(tag, elementty, int_width, vec_width, sbits, ubits, rraddr) \ | |
3677 { (ubits) > 0, rraddr } \ | |
3678 , | |
3679 ICETYPEARM32_TABLE | |
3680 #undef X | |
3681 }; | |
3682 // Before doing anything with a Mem operand, we need to ensure that the | 4143 // Before doing anything with a Mem operand, we need to ensure that the |
3683 // Base and Index components are in physical registers. | 4144 // Base and Index components are in physical registers. |
3684 Variable *Base = Mem->getBase(); | 4145 Variable *Base = Mem->getBase(); |
3685 Variable *Index = Mem->getIndex(); | 4146 Variable *Index = Mem->getIndex(); |
3686 ConstantInteger32 *Offset = Mem->getOffset(); | 4147 ConstantInteger32 *Offset = Mem->getOffset(); |
3687 assert(Index == nullptr || Offset == nullptr); | 4148 assert(Index == nullptr || Offset == nullptr); |
3688 Variable *RegBase = nullptr; | 4149 Variable *RegBase = nullptr; |
3689 Variable *RegIndex = nullptr; | 4150 Variable *RegIndex = nullptr; |
3690 if (Base) { | 4151 assert(Base); |
3691 RegBase = legalizeToReg(Base); | 4152 RegBase = legalizeToReg(Base); |
3692 } | 4153 bool InvalidImm = false; |
4154 assert(Ty < MemTraitsSize); | |
3693 if (Index) { | 4155 if (Index) { |
4156 assert(Offset == nullptr); | |
4157 assert(MemTraits[Ty].CanHaveIndex); | |
3694 RegIndex = legalizeToReg(Index); | 4158 RegIndex = legalizeToReg(Index); |
3695 if (!MemTraits[Ty].CanHaveIndex) { | |
3696 Variable *T = makeReg(IceType_i32, getReservedTmpReg()); | |
3697 _add(T, RegBase, RegIndex); | |
3698 RegBase = T; | |
3699 RegIndex = nullptr; | |
3700 } | |
3701 } | 4159 } |
3702 if (Offset && Offset->getValue() != 0) { | 4160 if (Offset && Offset->getValue() != 0) { |
3703 static constexpr bool SignExt = false; | 4161 assert(Index == nullptr); |
3704 if (!MemTraits[Ty].CanHaveOffset || | 4162 static constexpr bool ZeroExt = false; |
3705 !OperandARM32Mem::canHoldOffset(Ty, SignExt, Offset->getValue())) { | 4163 assert(MemTraits[Ty].CanHaveImm); |
3706 Variable *T = legalizeToReg(Offset, getReservedTmpReg()); | 4164 if (!OperandARM32Mem::canHoldOffset(Ty, ZeroExt, Offset->getValue())) { |
3707 _add(T, T, RegBase); | 4165 assert(RegBase->hasReg() && |
Jim Stichnoth
2015/11/08 20:05:51
Two separate asserts for better precision when it
John
2015/11/09 22:42:24
Done.
| |
3708 RegBase = T; | 4166 RegBase->getRegNum() == (int)getFrameOrStackReg()); |
3709 Offset = llvm::cast<ConstantInteger32>(Ctx->getConstantInt32(0)); | 4167 // We are a bit more lenient with invalid immediate when accessing the |
4168 // stack here, and then rely on legalizeStackSlots() to fix things as | |
4169 // appropriate. | |
4170 InvalidImm = true; | |
3710 } | 4171 } |
3711 } | 4172 } |
3712 | 4173 |
3713 // Create a new operand if there was a change. | 4174 // Create a new operand if there was a change. |
3714 if (Base != RegBase || Index != RegIndex) { | 4175 if (Base != RegBase || Index != RegIndex) { |
3715 // There is only a reg +/- reg or reg + imm form. | 4176 // There is only a reg +/- reg or reg + imm form. |
3716 // Figure out which to re-create. | 4177 // Figure out which to re-create. |
3717 if (RegBase && RegIndex) { | 4178 if (RegIndex) { |
3718 Mem = OperandARM32Mem::create(Func, Ty, RegBase, RegIndex, | 4179 Mem = OperandARM32Mem::create(Func, Ty, RegBase, RegIndex, |
3719 Mem->getShiftOp(), Mem->getShiftAmt(), | 4180 Mem->getShiftOp(), Mem->getShiftAmt(), |
3720 Mem->getAddrMode()); | 4181 Mem->getAddrMode()); |
3721 } else { | 4182 } else { |
3722 Mem = OperandARM32Mem::create(Func, Ty, RegBase, Offset, | 4183 Mem = OperandARM32Mem::create(Func, Ty, RegBase, Offset, |
3723 Mem->getAddrMode()); | 4184 Mem->getAddrMode()); |
3724 } | 4185 } |
3725 } | 4186 } |
3726 if (Allowed & Legal_Mem) { | 4187 if (Allowed & Legal_Mem) { |
3727 From = Mem; | 4188 From = Mem; |
3728 } else { | 4189 } else { |
3729 Variable *Reg = makeReg(Ty, RegNum); | 4190 Variable *Reg = makeReg(Ty, RegNum); |
3730 _ldr(Reg, Mem); | 4191 if (InvalidImm) { |
4192 // If Mem has an invalid immediate, we legalize it to a Reg using mov | |
4193 // instead of ldr because legalizeStackSlots() will later kick in and | |
4194 // fix the immediate for us. | |
4195 _mov(Reg, Mem); | |
4196 } else { | |
4197 _ldr(Reg, Mem); | |
4198 } | |
4199 | |
3731 From = Reg; | 4200 From = Reg; |
3732 } | 4201 } |
3733 return From; | 4202 return From; |
3734 } | 4203 } |
3735 | 4204 |
3736 if (auto *Flex = llvm::dyn_cast<OperandARM32Flex>(From)) { | 4205 if (auto *Flex = llvm::dyn_cast<OperandARM32Flex>(From)) { |
3737 if (!(Allowed & Legal_Flex)) { | 4206 if (!(Allowed & Legal_Flex)) { |
3738 if (auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Flex)) { | 4207 if (auto *FlexReg = llvm::dyn_cast<OperandARM32FlexReg>(Flex)) { |
3739 if (FlexReg->getShiftOp() == OperandARM32::kNoShift) { | 4208 if (FlexReg->getShiftOp() == OperandARM32::kNoShift) { |
3740 From = FlexReg->getReg(); | 4209 From = FlexReg->getReg(); |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3793 Variable *Reg = makeReg(Ty, RegNum); | 4262 Variable *Reg = makeReg(Ty, RegNum); |
3794 _movw(Reg, C); | 4263 _movw(Reg, C); |
3795 _movt(Reg, C); | 4264 _movt(Reg, C); |
3796 return Reg; | 4265 return Reg; |
3797 } else { | 4266 } else { |
3798 assert(isScalarFloatingType(Ty)); | 4267 assert(isScalarFloatingType(Ty)); |
3799 // Load floats/doubles from literal pool. | 4268 // Load floats/doubles from literal pool. |
3800 // TODO(jvoung): Allow certain immediates to be encoded directly in an | 4269 // TODO(jvoung): Allow certain immediates to be encoded directly in an |
3801 // operand. See Table A7-18 of the ARM manual: "Floating-point modified | 4270 // operand. See Table A7-18 of the ARM manual: "Floating-point modified |
3802 // immediate constants". Or, for 32-bit floating point numbers, just | 4271 // immediate constants". Or, for 32-bit floating point numbers, just |
3803 // encode the raw bits into a movw/movt pair to GPR, and vmov to an SREG, | 4272 // encode the raw bits into a movw/movt pair to GPR, and vmov to an SREG |
3804 // instead of using a movw/movt pair to get the const-pool address then | 4273 // instead of using a movw/movt pair to get the const-pool address then |
3805 // loading to SREG. | 4274 // loading to SREG. |
3806 std::string Buffer; | 4275 std::string Buffer; |
3807 llvm::raw_string_ostream StrBuf(Buffer); | 4276 llvm::raw_string_ostream StrBuf(Buffer); |
3808 llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx); | 4277 llvm::cast<Constant>(From)->emitPoolLabel(StrBuf, Ctx); |
3809 llvm::cast<Constant>(From)->setShouldBePooled(true); | 4278 llvm::cast<Constant>(From)->setShouldBePooled(true); |
3810 Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); | 4279 Constant *Offset = Ctx->getConstantSym(0, StrBuf.str(), true); |
3811 Variable *BaseReg = makeReg(getPointerType()); | 4280 Variable *BaseReg = makeReg(getPointerType()); |
3812 _movw(BaseReg, Offset); | 4281 _movw(BaseReg, Offset); |
3813 _movt(BaseReg, Offset); | 4282 _movt(BaseReg, Offset); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3863 } | 4332 } |
3864 | 4333 |
3865 OperandARM32Mem *TargetARM32::formMemoryOperand(Operand *Operand, Type Ty) { | 4334 OperandARM32Mem *TargetARM32::formMemoryOperand(Operand *Operand, Type Ty) { |
3866 OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand); | 4335 OperandARM32Mem *Mem = llvm::dyn_cast<OperandARM32Mem>(Operand); |
3867 // It may be the case that address mode optimization already creates an | 4336 // It may be the case that address mode optimization already creates an |
3868 // OperandARM32Mem, so in that case it wouldn't need another level of | 4337 // OperandARM32Mem, so in that case it wouldn't need another level of |
3869 // transformation. | 4338 // transformation. |
3870 if (Mem) { | 4339 if (Mem) { |
3871 return llvm::cast<OperandARM32Mem>(legalize(Mem)); | 4340 return llvm::cast<OperandARM32Mem>(legalize(Mem)); |
3872 } | 4341 } |
3873 // If we didn't do address mode optimization, then we only have a base/offset | 4342 // If we didn't do address mode optimization, then we only have a |
3874 // to work with. ARM always requires a base register, so just use that to | 4343 // base/offset to work with. ARM always requires a base register, so |
3875 // hold the operand. | 4344 // just use that to hold the operand. |
3876 Variable *Base = legalizeToReg(Operand); | 4345 Variable *Base = legalizeToReg(Operand); |
3877 return OperandARM32Mem::create( | 4346 return OperandARM32Mem::create( |
3878 Func, Ty, Base, | 4347 Func, Ty, Base, |
3879 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32))); | 4348 llvm::cast<ConstantInteger32>(Ctx->getConstantZero(IceType_i32))); |
3880 } | 4349 } |
3881 | 4350 |
3882 Variable64On32 *TargetARM32::makeI64RegPair() { | 4351 Variable64On32 *TargetARM32::makeI64RegPair() { |
3883 Variable64On32 *Reg = | 4352 Variable64On32 *Reg = |
3884 llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); | 4353 llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
3885 Reg->setMustHaveReg(); | 4354 Reg->setMustHaveReg(); |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4266 // Technically R9 is used for TLS with Sandboxing, and we reserve it. | 4735 // Technically R9 is used for TLS with Sandboxing, and we reserve it. |
4267 // However, for compatibility with current NaCl LLVM, don't claim that. | 4736 // However, for compatibility with current NaCl LLVM, don't claim that. |
4268 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; | 4737 Str << ".eabi_attribute 14, 3 @ Tag_ABI_PCS_R9_use: Not used\n"; |
4269 } | 4738 } |
4270 | 4739 |
4271 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM]; | 4740 llvm::SmallBitVector TargetARM32::TypeToRegisterSet[IceType_NUM]; |
4272 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM]; | 4741 llvm::SmallBitVector TargetARM32::RegisterAliases[RegARM32::Reg_NUM]; |
4273 llvm::SmallBitVector TargetARM32::ScratchRegs; | 4742 llvm::SmallBitVector TargetARM32::ScratchRegs; |
4274 | 4743 |
4275 } // end of namespace Ice | 4744 } // end of namespace Ice |
OLD | NEW |